4

NHibernate を使用して多数のエンティティを作成し、それらを ISession にアタッチしてから、トランザクションを使用して変更をデータベースにコミットしています。コードサンプルは次のとおりです。

ISession _context = SessionProvider.OpenSession();

//Create new entities
for(int i=0; i<100; i++)
{
    MyEntity entity = new MyEntity(i);

    //Attach new entity to the context
    _context.Save(entity);
}

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Flush the session
    tx.Commit();
}

行 _context.Save() は単に ISession に新しいエンティティを認識させるだけであるという印象を受けましたが、行 tx.Commit() を介してセッションをフラッシュするまで、変更はデータベースに永続化されません。

私が観察したことは、_context.Save() を呼び出すたびに、データベースが新しいエンティティを取得することです。その結果、データベースへの個々の呼び出しが多すぎます。

ISession.Save() が自動的に変更を永続化する理由を知っている人はいますか? NHibernate の動作について何か誤解していませんか? ありがとう。

***編集-明確にするために(2つの提案された回答に照らして)-ここでの私の問題は、_context.Save()を呼び出すとすぐにデータベースが更新されることです。私はこれが起こるとは思わない。tx.Commit() を呼び出すまで、データベースに何も挿入されないことを期待しています。残念ながら、これまでに提案された2つの回答はどちらもこれに役立ちません。

ID ジェネレーターに関するいくつかの優れた情報については、こちらを参照してください。

4

6 に答える 6

7

試す:

using(Session _context = SessionProvider.OpenSession())
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();
}
于 2011-06-26T16:37:25.347 に答える
6

どの ID ジェネレーターを使用していますか? Id フィールドの値を生成するためにMSSQL/MySQLIdentityや Oracle などの挿入後のジェネレータを使用している場合、それが問題です。sequence

明らかになった NHibernate POID ジェネレーターから:

ポスト インサート ジェネレーターは、その名前が示すように、エンティティがデータベースに格納された後に ID を割り当てます。データベースに対して select ステートメントが実行されます。これらには多くの欠点があり、私の意見では、ブラウンフィールド プロジェクトでのみ使用する必要があります。これらのジェネレーターは、NH チームとして推奨しないものです。

いくつかの欠点は次のとおりです。

  1. これらの戦略を使用すると、作業単位が壊れます。FlushMode.Commit を使用しているかどうかは関係ありません。各 Save は、DB に対する挿入ステートメントになります。ベスト プラクティスとして、挿入をコミットまで延期する必要がありますが、ポスト インサート ジェネレーターを使用すると、保存時にコミットされます (これは UoW が行うことではありません)。
  2. これらの戦略はバッチャーを無効にします。一度に複数のクエリを送信することを利用することはできません (保存時にデータベースに移動する必要があるため)
于 2011-06-26T19:52:10.717 に答える
2

構成でバッチサイズを設定できます。

<add key="hibernate.batch_size" value="10" /> 

または、コードで設定することもできます。また、保存は必ずトランザクション スコープ内で行ってください。

于 2011-06-26T20:12:43.843 に答える
1

FlushMode を Commit に設定してみてください。

ISession _context = SessionProvider.OpenSession();
context.FlushMode = FlushMode.Commit;

バッチサイズを設定するというピアの提案も良いです。

私の理解では、データベース ID 列を使用する場合、NHibernate は、外部キーを取得するため、またはクエリが期待される結果を確実に返すために挿入を実行する必要がない限り、セッションがフラッシュされるまで挿入を延期します。

于 2011-06-26T21:00:39.060 に答える
0

どうですか:

ISession _context = SessionProvider.OpenSession();

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();

}
于 2011-06-26T16:39:20.133 に答える
0

良い

  1. 反逆者の答えは、マッピングに応じて可能性があります
  2. 明示的なトランザクションを使用していません (StuffHappens の回答)
  3. デフォルトのフラッシュモードは自動であり、複雑になります(Jamie Ideの回答)
  4. 何らかの変更により、nhibernate API を使用してクエリを作成した場合、デフォルトの動作は、最初にキャッシュをデータベースにフラッシュして、それらのクエリの結果がセッション エンティティ表現と一致するようにすることです。
于 2011-06-27T06:52:13.707 に答える