NHibernate Session.Flush()在未发生更新时发送更新查询

时间:2008-08-29 17:49:31

标签: c# .net nhibernate

我有一个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将更新语句传递给db,并导致外键违规。如果我不运行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 = ?]

没有参数显示为传递。

3 个答案:

答案 0 :(得分:45)

每当处理NHibernate时,都要小心使用NULLable字段。如果您的字段在DB中为NULL,请确保相应的.NET类也使用Nullable类型。否则,会发生各种奇怪的事情。症状通常是NHibernate将尝试更新DB中的记录,即使您从数据库中读取实体后没有更改任何字段。

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

  1. NHibernate使用ADO.NET
  2. 从DB检索原始实体的数据
  3. NHibernate构造实体并设置其属性
  4. 如果DB字段包含NULL,则该属性将设置为其类型的默认值:
    • 引用类型的属性将设置为null
    • 整数和浮点类型的属性将设置为0
    • 布尔类型的属性将设置为false
    • DateTime类型的属性将设置为DateTime.MinValue
  5. 现在,当提交事务时,NHibernate会将该属性的值与从DB读取的原始字段值进行比较,并且由于该字段包含NULL但该属性包含非null值,因此 NHibernate会考虑该属性脏,并强制更新enity。
  6. 这不仅会损害性能(每次检索实体时都会获得额外的数据库往返和额外更新),但这也可能导致很难使用DateTime列来解决错误。实际上,当DateTime属性初始化为其默认值时,它设置为1/1/0001。当此值保存到DB时,ADO.NET的SqlClient无法将其转换为有效的SqlDateTime值,因为可能的最小SqlDateTime是1/1/1753 !!!

    最简单的解决方法是使类属性使用Nullable类型,在本例中为“DateTime?”。或者,您可以通过实现IUserType及其Equals方法来正确地比较DbNull.Value与值类型的任何默认值来实现自定义类型映射器。在我们的例子中,当将1/1/0001与DbNull.Value进行比较时,Equals需要返回true。实现一个功能齐全的IUserType并不是那么难,但它确实需要NHibernate琐事的知识,所以如果你选择这样做,准备做一些实质性的谷歌搜索。

答案 1 :(得分:16)

之前我曾经看过一次我的模型之一没有正确映射(没有正确使用可空类型)。请你粘贴模型和贴图吗?

答案 2 :(得分:0)

当我尝试使用access =“noop”隐藏多对多行李的反向末端时,我也在NH 2.0.1中遇到过这个问题(提示:这不起作用)。

将它们转换为access =“field”+在类上添加一个字段修复了问题。虽然很难追踪它们。