34

NHibernateセッションがあります。このセッションでは、正確に1つの操作を実行しています。これは、次のコードを実行してリストを取得することです。

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

Session.Flush()の最後に電話をかけていHttpRequestますが、が表示されHibernateAdoExceptionます。NHibernateがデータベースに更新ステートメントを渡し、外部キー違反を引き起こしています。を実行しない場合flush、リクエストは問題なく完了します。ここでの問題は、このコードが他の領域で再利用されるため、他のセッション内で変更が発生した場合に備えて、フラッシュを配置する必要があることです。不足している可能性のある別の構成設定はありますか?


例外のコードは次のとおりです。

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

渡されたものとして表示されているパラメーターはありません。

4

3 に答える 3

45

NHibernateを扱うときは、常にNULL可能フィールドに注意してください。DBでフィールドがNULL可能である場合は、対応する.NETクラスもNULL可能型を使用していることを確認してください。そうでなければ、あらゆる種類の奇妙なことが起こります。症状は通常、データベースからエンティティを読み取ってからフィールドを変更していなくても、NHibernateがDBのレコードを更新しようとすることです。

次のシーケンスは、これが発生する理由を説明しています。

  1. NHibernateは、ADO.NETを使用してDBから生のエンティティのデータを取得します
  2. NHibernateはエンティティを構築し、そのプロパティを設定します
  3. DBフィールドにNULLが含まれている場合、プロパティはそのタイプのデフォルト値に設定されます。
    • 参照型のプロパティはnullに設定されます
    • 整数型と浮動小数点型のプロパティは0に設定されます
    • ブール型のプロパティはfalseに設定されます
    • DateTimeタイプのプロパティはDateTime.MinValueに設定されます
  4. これで、トランザクションがコミットされると、NHibernateはプロパティの値をDBから読み取った元のフィールド値と比較します。フィールドにはNULLが含まれていますが、プロパティにはnull以外の値が含まれているため、NHibernateはプロパティをダーティと見なし、強制的に更新します。実体の。

これにより、パフォーマンスが低下するだけでなく(DBへのラウンドトリップが増え、エンティティを取得するたびに更新が増える)、DateTime列のエラーのトラブルシューティングが困難になる可能性があります。実際、DateTimeプロパティがデフォルト値に初期化されると、1/1/0001に設定されます。この値がDBに保存されると、可能な最小のSqlDateTimeは1/1/1753であるため、ADO.NETのSqlClientはそれを有効なSqlDateTime値に変換できません。

最も簡単な修正は、クラスプロパティでNullable型(この場合は「DateTime?」)を使用するようにすることです。または、Equalsメソッドを使用してIUserTypeを実装し、DbNull.Valueを値型のデフォルト値と適切に比較することで、カスタム型マッパーを実装することもできます。この場合、Equalsは1/1/0001をDbNull.Valueと比較するときにtrueを返す必要があります。フル機能のIUserTypeを実装することはそれほど難しいことではありませんが、NHibernateトリビアの知識が必要なので、そのようにすることを選択した場合は、かなりのグーグルを行う準備をしてください。

于 2009-09-16T17:09:10.633 に答える
16

モデルの 1 つが正しくマップされていなかった (null 許容型を正しく使用していなかった) ときに、これを以前に一度見たことがあります。モデルとマッピングを貼り付けていただけますか?

于 2008-08-29T18:35:23.207 に答える
0

また、access = "noop"を使用して多対多バッグの逆端を非表示にしようとしたときに、NH 2.0.1でこの問題が発生しました(ヒント:これは機能しません)。

それらをaccess="field"に変換し、クラスにフィールドを追加すると、問題が修正されました。しかし、それらを追跡するのはかなり難しいです。

于 2009-07-18T04:20:40.977 に答える