2011-12-27 3 views
2

Userというタイプの100個のオブジェクトがあり、各ユーザーに1対1の参照があるとします。 NHibernate configのバッチサイズは50に設定されています。したがって、100個のオブジェクトすべてを削除すると、NHibernateは200個のDBへの接続を開始します。私はそれぞれの接続で50のクエリで4つの接続でそれらを削除したいと思います。NHibernate:オブジェクトのセットを削除するには?

public void BatchDelete(IEnumerable<T> entitiesToDelete) 
    { 
     int batchSzie = Session.GetSessionImplementation().Batcher.BatchSize; 
     int batchedInsertsCount = 0; 
     foreach (var entity in entitiesToDelete) 
     { 
      batchedInsertsCount++; 
      Session.Delete(entity); 
      if (batchedInsertsCount % batchSzie == 0) 
      { 
       Session.Flush(); 
       Session.Clear(); 
      } 
     } 
    } 

EDIT:以下のコードは期待通りに動作します私のバッチ挿入法からのコピー/ペーストである私は、取引にいることを言及するのを忘れてしまいました。

答えて

0

まず、セッションのバッチサイズ(session.BatchSize())を設定していないので、セッションファクトリが作成されたときの既定値や設定値が使用されます。しかしさらに重要なのは、バッチ削除をサポートしていないことです。 session.BatchSize()を正しく設定しても、(少なくともNHibernate 3.2とSQL Server 2008では)効果はありません。 Ayende has a blog post that shows how to solve the problem

+0

!0x Toni。私もその記事を読んだが、2006年に書かれたので、2011年に修正されたと思った。バッチ削除をしない理由があるかもしれない。 – mynkow

4
  Session.Flush(); 
      Session.Clear(); 

は、通常の取引の追加を開始し、削除し、あなたが何か間違ったことをやっていることを示し:

if (batchedInsertsCount % batchSzie == 0) 

異なるアプローチは、削除やでと、クエリすることができます:

  // fill batch with id list of items you want to delete 
      _session.CreateQuery(String.Format("DELETE FROM TABLENAME WHERE Id IN (:idsList)", _domainObject.Name)) 
        .SetParameterList("idsList", batch.ToArray()) 
        .ExecuteUpdate(); 

メイクsqlserverに与えることができるパラメータの最大値である2100の最大IDを確認してください。

+0

私は取引中であることを忘れていました。なぜフラッシュ/クリアが悪いのですか?例えば、挿入の前に削除を処理する場合、Flushは非常に便利です。とにかく、フラッシュ/クリアを削除した後も、まだ200の接続が残っています。 :| – mynkow

+0

Session.Flush()の必要性。通常、(ほとんどの場合)何かがコードレビューで正しくないことを示します。サンプルコードのように削除すると、200のクエリがデータベースに送信されます。クエリは、バッチサイズである50個のクエリのバッチで送信されます。フラッシングはそれを変更しません。あなたができることは、1つのクエリですべてのレコードを削除するためにカスタムの削除クエリを作成することです: – Peter

+0

DELETEステートメントの周りで使用されるString.Formatステートメントはここでは役に立ちませんか? "{0}"はありませんか? – PandaWood

3

あなたはそれを複雑にしています。

必要なバッチサイズを設定し、必要なすべてのSession.Deleteコールを実行してから、トランザクションをコミットします。

NHibernateはentitiesToDelete.Count()/batch sizeのクエリを実行します。

ここでのコードサンプルがあります:

using (var session = sessionFactory.OpenSession()) 
using (var tx = session.BeginTransaction()) 
{ 
    foreach (var foo in session.Query<Foo>()) 
     session.Delete(foo); 
    tx.Commit(); 
} 

とサンプル構成:

var config = new Configuration(); 
config.SessionFactory() 
     .Integrate.Using<MsSql2008Dialect>().Connected.Using("...") 
     .BatchingQueries.Each(10); 

(私はバッチサイズのための明示的な値を設定するんだけど、NH 20 IIRCに3.2デフォルト)

カスケードされたコレクションがある場合は、その削除がDBによって処理されていることを確認する必要があります。あなたがON DELETE CASCADEとしてFKSを定義し、NHはそのことについて知っている必要があり

FooBarsのコレクションがあり、この場合、

<class name="Foo"> 
    <id ...>...</id> 
    <bag name="Bars" inverse="true" cascade="all"> 
    <key column="FooId" on-delete="cascade" /> 
    <one-to-many class="Bar" /> 
    </bag> 
</class> 
<class name="Bar"> 
    <id ...>...</id> 
    <many-to-one name="Foo" column="FooId" /> 
</class> 

は、FooId列に持続しました。

+1

NH 3.2で動作しません。バッチ削除はありません:( – mynkow

+0

はい、私はそれを確認しました。 –

+0

オブジェクトにコレクションやその他の関連オブジェクトがあるかどうかは重要ですか? – mynkow

関連する問題