NHibernate ISession Flush:いつ、どこで、なぜ使用するのですか?


187

私は徹底的に混乱ことの一つは、の使用であるsession.Flushと併せて、session.Commitsession.Close

時々session.Close機能します。たとえば、必要なすべての変更をコミットします。エラーが発生した場合にロールバックするように選択できるように、トランザクション、または複数の作成/更新/削除を伴う作業単位がある場合は、コミットを使用する必要があることを知っています。

しかし、時々私は本当に背後にあるロジックに困惑しsession.Flushます。私はあなたがsession.SaveOrUpdate()続いてフラッシュを持っている例を見ました、しかし私がフラッシュを取り除くとき、それはとにかくうまく働きます。Flushステートメントでセッションがタイムアウトしたことを示すエラーが発生することがあり、それを削除することで、そのエラーに遭遇しないようにしました。

誰かがフラッシュをどこでいつ使用するかについて良いガイドラインはありますか?これについてNHibernateのドキュメントをチェックアウトしましたが、それでも簡単な答えは見つかりません。

回答:


236

簡単に:

  1. 常にトランザクションを使用
  2. 使用しないでくださいClose()。代わりISessionに、usingステートメント内で呼び出しをラップするか、ISessionのライフサイクルを別の場所で管理してください

ドキュメントから:

ISession随時、ADO.NET接続の状態をメモリに保持されているオブジェクトの状態と同期するために必要なSQLステートメントを実行します。このプロセス、フラッシュは、デフォルトで次の時点で発生します

  • Find()またはのいくつかの呼び出しからEnumerable()
  • から NHibernate.ITransaction.Commit()
  • から ISession.Flush()

SQLステートメントは次の順序で発行されます

  1. すべてのエンティティの挿入。対応するオブジェクトが保存されたのと同じ順序で ISession.Save()
  2. すべてのエンティティの更新
  3. すべてのコレクションの削除
  4. すべてのコレクション要素の削除、更新、および挿入
  5. すべてのコレクション挿入
  6. すべてのエンティティの削除。対応するオブジェクトが削除されたのと同じ順序で ISession.Delete()

(例外として、ネイティブID生成を使用するオブジェクトは、保存時に挿入されます。)

明示的に指定する場合を除いてFlush()、セッションがADO.NET呼び出しをいつ実行するかについての保証はまったくなく、実行順序のみが保証されます。ただし、NHibernateは、ISession.Find(..)メソッドが古いデータを返さないことを保証します。また、間違ったデータを返しません。

デフォルトの動作を変更して、フラッシュの発生頻度を下げることができます。FlushMode唯一のコミット時にフラッシュ(とNHibernateはのときにのみ:クラスには、3つの異なるモードを定義しITransaction、APIが使用されている)をフラッシュが自動的にルーチン、またはしない限り、決してフラッシュ説明使用してFlush()明示的に呼び出されます。最後のモードは、ISessionが開いたままで、長時間切断されている、長時間実行される作業単位に役立ちます。

...

このセクションも参照しください。

セッションの終了には、4つの異なるフェーズが含まれます。

  • セッションをフラッシュする
  • トランザクションをコミットする
  • セッションを閉じる
  • 例外を処理する

セッションのフラッシュ

たまたまITransactionAPI を使用している場合は、この手順について心配する必要はありません。トランザクションがコミットされると、暗黙的に実行されます。それ以外の場合はISession.Flush()、すべての変更がデータベースと同期されていることを確認するために呼び出す必要があります。

データベーストランザクションのコミット

NHibernate ITransaction APIを使用している場合、これは次のようになります。

tx.Commit(); // flush the session and commit the transaction

ADO.NETトランザクションを自分で管理している場合は、手動Commit()でADO.NETトランザクションを実行する必要があります。

sess.Flush();
currentTransaction.Commit();

変更をコミットしないことにした場合:

tx.Rollback();  // rollback the transaction

または:

currentTransaction.Rollback();

トランザクションをロールバックする場合は、現在のセッションをすぐに閉じて破棄し、NHibernateの内部状態が一貫していることを確認する必要があります。

ISessionを閉じる

ISession.Close()セッションの終了をマークする呼び出し。Close()の主な影響は、ADO.NET接続がセッションによって解放されることです。

tx.Commit();
sess.Close();

sess.Flush();
currentTransaction.Commit();
sess.Close();

独自の接続を提供Close()した場合、それへの参照を返すため、手動で閉じるか、プールに戻すことができます。それ以外の場合Close()は、プールに戻します。


2
私にとって、この行が重要でした:「Close()の主な意味は、ADO.NET接続がセッションによって解放されることです。」ISession.Close()を呼び出さないと、dbタイムアウトが発生するまで接続がいっぱいになります。:o
dave thieben

通常:セッションを開くsession.BeginTransaction()work ... session.Transaction.Commit()session.BeginTransaction()work ... session.Transaction.Commit()session.BeginTransaction()work .. session.Transaction.Commit ()セッションを破棄します。
アジャイルジェダイ

見事な書き込みと+1など-ただし、「閉じることは絶対に使用しない」の後に「トランザクションをロールバックする場合はすぐに現在のセッションを閉じて破棄する必要があります」と言うため、編集が必要になると思います
SpaceBison

SQLステートメントの順序を変更できますか?対応するテーブルに制約があるため、エンティティオブジェクトに対して更新を実行し、挿入する必要があることを意味します。
bob_saginowski 2017

14

NHibernate 2.0以降、DB操作にはトランザクションが必要です。したがって、ITransaction.Commit()呼び出しは必要なフラッシュを処理します。何らかの理由でNHibernateトランザクションを使用していない場合、セッションの自動フラッシュは行われません。


1

ISessionは、ADO.NET接続の状態をメモリに保持されているオブジェクトの状態と同期するために必要なSQLステートメントを時々実行します。

そしていつも使う

 using (var transaction = session.BeginTransaction())
 {
     transaction.Commit();
 }

変更がコミットされた後、データベースに保存するためにこの変更よりもtransaction.Commit();を使用します。


0

以下は、session.Flush()なしでは失敗するコードの2つの例です。

http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html

この最後に、ID挿入をオンに設定し、エンティティを保存してフラッシュし、ID挿入をオフに設定するコードのセクションが表示されます。このフラッシュがなければ、ID挿入のオンとオフを設定してからエンティティを保存しているようです。

Flush()を使用すると、何が起こっているかをより詳細に制御できます。

次に別の例を示します。

TransactionScope内でのNServiceBusメッセージの送信

なぜこれが原因なのかは完全にはわかりませんが、Flush()によってエラーが発生しなくなりました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.