2011-07-05 3 views
8

NHibernateで作業中にTooManyRowsAffectedExceptionが発生しました。ここでTooManyRowsAffectedException with encrypted triggersのような別のバッチャーを注入するか、SET NOCOUNT ONを使用するようにデータベースのトリガーを変更して回避策を見ました。私はデータベースを変更したくない - それは100以上のテーブルがすべて一緒に関連しているので非常に複雑で、他のアプリケーションがそれを使用してから混乱したくない。なぜこの例外が発生するのか分かりません。私が行うのは、私がチェックする値がいくつかあるSampleオブジェクトがあり、その値が所定の基準に合う場合は、Sample.IsDone行を 'Y'に設定します(データベース内のブール値はすべて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です。私は1行しか変更しないので、なぜ2行更新しますか?

ご協力いただきありがとうございます。

EDIT:

私はサンプルが更新されたとき(コンテナのサンプルが含まれている)コンテナテーブルの行を更新、データベース内のトリガーがありますので、その原因であることを見つけることができました。 NHibernateがこのトリガについて知って、適切な数の行が更新されることを期待するように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(); 
    } 
} 

EDIT:流暢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

私はFluent NHibernateを使用していませんが、NHibernateの設定でこれがどこに当てはまるのか分かりますか?私はどこでそれを書くべきか分かりません(私はClassMapを使用せず、それが何であるかを知っていませんし、SqlInsertなどの関数も見ていません)。 – Carl

+0

私の答えを編集してください。うまくいけば、HBMを手作業で作成しているわけではありません。しかし、もしFluent NHibernateやNHibernate 3.0の新しい流暢なマッピング機能があなたにとって何ができるのかは間違いありません。 –

+1

ありがとう。はい、私は手でHBMを作成していますが、今は問題ではありません(これは特に難しいとは思いません)。 – Carl

2

実行されるSQLをプロファイラで確認してください。 anjlab sql profilerは常に私のためにトリックをしました。

その後、そのテーブルにトリガーがあるかどうかを確認してください。おそらく問題が発生している可能性があります。

EDIT

あなたがここにあなたのようにトリガーを変更する必要があります。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にトリガーがデータベース内の他のエンティティを更新したことを伝えるために何もすることはできません.Sexto Saezのように無視します。ただし、EventListenersを使用してコード内でトリガーアクションを実行できます。または、トランザクションの残りの部分について更新が重要でない場合は、トリガの開始時にSET NOCOUNTをONに設定し、最後にSET NOCOUNTをOFFに設定します。

関連する問題