2011-07-05 55 views
8

我刚刚在使用NHibernate时遇到了TooManyRowsAffectedException,我通过注入了一个不同的batcher,例如TooManyRowsAffectedException with encrypted triggers,或者修改了数据库中的触发器以使用SET NOCOUNT ON(我不能使用这个我不想修改数据库 - 这是非常复杂的,有超过一百个表全部关联在一起,我不想因为其他应用程序使用它而弄乱它)。我不明白的是为什么会发生这种例外。我所做的只是我有一个Sample对象,它有两个我检查的值,如果这些值符合给定的条件,我将Sample.IsDone行设置为'Y'(在我们的数据库中,所有布尔值都由a char Y或N)。代码非常简单:如何告诉NHibernate触发器更新另一个表?

IQueryable<Sample> samples = session.Query<Sample>().Where(s =­­> s.Value == desiredValue); 
foreach (Sample sample in samples) 
{ 
    sample.IsDone = 'Y'; 
    session.Flush(); // Throws TooManyRowsAffectedException 
} 
session.Flush(); // Throws TooManyRowsAffectedException 

Flush调用会抛出是否将其放入循环或外部。有什么我做错了,还是只与数据库的方式有关?我试着在Flush()之前调用SaveOrUpdate()函数,但它没有改变任何东西。我知道我可以解决这个异常,但我更愿意理解问题的根源。

注意:在例外情况中,它告诉我实际的行数是2,预期是1.为什么它更新2行,因为我只更改了1行?

谢谢大家的帮助!

编辑:

我能找出的是,原因是因为在数据库中的触发器在集装箱表(容器盛样品)当样品更新更新一行。有没有一种方法来配置NHibernate,以便它知道这个触发器,并期望正确的行数得到更新?

回答

5

唯一的工作,我身边已经找到下面使用功能NHibernate的代码片段所示。这很丑陋,因为它很难将SQL编码到映射中,但它确实有效。 Check属性设置为None,因此计数被忽略。我不知道您是否可以使用直线HBM文件来完成此操作,但可能有办法。如果在NHibernate(或Fluent NH)中有一个配置选项来设置预期的更新行数或在需要时忽略它,那将会很棒。

public class OrderMap : ClassMap<Order> 
{ 
    public OrderMap() 
    { 
     Id(c => c.Id, "order_id").GeneratedBy.Native(); 

     Table("order"); 

     Map(c => c.GroupId, "group_id"); 
     Map(c => c.Status, "status"); 
     Map(c => c.LocationNumber, "location"); 

     SqlInsert("insert into order (group_id, status, location) values (?, ?, ?)").Check.None(); 
     SqlUpdate("update order set group_id = ?, status = ?, location = ? where order_id = ?")).Check.None(); 
     SqlDelete("delete order where order_id = ?").Check.None(); 
    } 
} 

编辑: 对于那些不幸的人是不知道功能NHibernate的或爱痛苦的一代的手工HBM文件,这里是该样本映射HBM文件:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true"> 
    <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Your.DomainModel.Entities.Order, Your.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="order"> 
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0"> 
     <column name="order_id" /> 
     <generator class="identity" /> 
    </id> 
    <property name="GroupId" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="group_id" /> 
    </property> 
    <property name="Status" type="System.Int16, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="status" /> 
    </property> 
    <property name="LocationNumber" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <column name="loc_num" /> 
    </property> 
    <sql-insert check="none">insert into order (group_id, status, location) values (?, ?, ?)</sql-insert> 
    <sql-update check="none">update order set group_id = ?, status = ?, location = ? where order_id = ?</sql-update> 
    <sql-delete check="none">delete order where order_id = ?</sql-delete> 
    </class> 
</hibernate-mapping> 
+0

我不使用流利的NHibernate,你知道这适用于NHibernate设置?我不知道应该在哪里写(我不使用任何ClassMap,也不知道它是什么,而且我没有看到像SqlInsert之类的函数)。 – Carl

+0

请参阅编辑我的答案。希望你没有手动创建HBM。但是,如果是,肯定看看Fluent NHibernate或NHibernate 3.0中新的流畅映射能力可以为你做什么。 –

+1

谢谢你。是的,我正在手动创建HBM,但现在不是问题(我不觉得这特别困难)。 – Carl

2

用分析器检查执行的sql。 anjlab sql profiler总是为我做的伎俩。

之后,检查是否在该表上有触发器 - 可能会造成一些麻烦。

编辑

你应该改变你的触发喜欢这里:http://www.codewrecks.com/blog/index.php/2009/03/25/nhibernate-and-toomanyrowsaffectedexception/

+0

感谢您的链接。你是对的我看到有一个触发器在更新示例时更新Container(包含示例)的last_updated_date列。你知道是否有办法告诉NHibernate期望吗? – Carl

+0

我认为这将会发生,因为我没有找到任何其他方式来使它工作,但由于有100多个客户端使用数据库与10多个不同的应用程序,我不知道是否修改触发器可以使其他应用程序停止工作。 – Carl

1

有没有什么可以告诉NHibernate触发器更新数据库中的其他实体,除非像Sixto Saez在他的答案中所示的那样忽略它。但是,您可以使用EventListeners在代码中执行触发器操作。或者在触发开始时设置SET NOCOUNT ON,并在结束时设置SET NOCOUNT OFF,如果更新对于其余交易无关紧要。

相关问题