2011-07-05 58 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,如果更新對於其餘交易無關緊要。

相關問題