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 时,请务必小心使用 NULLable 字段。如果您的字段在 DB 中为 NULLable,请确保相应的 .NET 类也使用 Nullable 类型。否则,会发生各种奇怪的事情。症状通常是 NHibernate 将尝试更新 DB 中的记录,即使自从您从数据库中读取实体后您还没有更改任何字段。

以下序列解释了为什么会发生这种情况:

  1. NHibernate 使用 ADO.NET 从数据库中检索原始实体的数据
  2. NHibernate 构造实体并设置其属性
  3. 如果 DB 字段包含 NULL,则属性将设置为其类型的默认值:
    • 引用类型的属性将设置为 null
    • 整数和浮点类型的属性将设置为 0
    • boolean 类型的属性将设置为 false
    • DateTime 类型的属性将设置为 DateTime.MinValue
    • 等等
  4. 现在,当事务提交时,NHibernate 将属性的值与它从 DB 读取的原始字段值进行比较,并且由于该字段包含 NULL 但属性包含非空值,NHibernate 认为该属性是脏的,并强制更新的实体。

Not only this hurts performance (you get extra round-trip to DB and extra update every time you retrieve the entity) but it also may cause hard to troubleshoot errors with DateTime columns. Indeed, when DateTime property is initialized to its default value it's set to 1/1/0001. When this value is saved to DB, ADO.NET's SqlClient can't convert it to a valid SqlDateTime value since the smallest possible SqlDateTime is 1/1/1753!!!

The easiest fix is to make the class property use Nullable type, in this case "DateTime?". Alternatively, you could implement a custom type mapper by implementing IUserType with its Equals method properly comparing DbNull.Value with whatever default value of your value type. In our case Equals would need to return true when comparing 1/1/0001 with DbNull.Value. Implementing a full-functional IUserType is not really that hard but it does require knowledge of NHibernate trivia so prepare to do some substantial googling if you choose to go that way.

于 2009-09-16T17:09:10.633 回答
16

当我的一个模型未正确映射(未正确使用可空类型)时,我曾经见过这种情况。能否请您粘贴您的模型和映射?

于 2008-08-29T18:35:23.207 回答
0

当我尝试使用 access="noop" 隐藏多对多包的反端时,我在 NH 2.0.1 中也遇到了这个问题(提示:这不起作用)。

将它们转换为 access="field" + 在类上添加一个字段解决了这个问题。不过很难追踪到它们。

于 2009-07-18T04:20:40.977 回答