NHibernate ISession Flush: Wo und wann und warum?

187

Eines der Dinge, die mich gründlich verwirren, ist die Verwendung von session.Flush, in Verbindung mit session.Commitund session.Close.

Manchmal session.Closefunktioniert es, z. B. werden alle Änderungen festgeschrieben, die ich benötige. Ich weiß, dass ich Commit verwenden muss, wenn ich eine Transaktion oder eine Arbeitseinheit mit mehreren Erstellungen / Aktualisierungen / Löschungen habe, damit ich bei einem Fehler ein Rollback durchführen kann.

Aber manchmal werde ich wirklich von der Logik dahinter behindert session.Flush. Ich habe Beispiele gesehen, bei denen session.SaveOrUpdate()ein Flush gefolgt ist, aber wenn ich Flush entferne, funktioniert es trotzdem einwandfrei. Manchmal sind in der Flush-Anweisung Fehler aufgetreten, die besagen, dass die Sitzung abgelaufen ist, und durch Entfernen wurde sichergestellt, dass ich nicht auf diesen Fehler gestoßen bin.

Hat jemand eine gute Richtlinie, wo oder wann ein Flush verwendet werden soll? Ich habe die NHibernate-Dokumentation dazu überprüft, kann aber immer noch keine eindeutige Antwort finden.

Jon Limjap
quelle

Antworten:

236

Kurz:

  1. Verwenden Sie immer Transaktionen
  2. Nicht verwenden Close(), sondern Ihre Anrufe ISessionin eine usingAnweisung einschließen oder den Lebenszyklus Ihrer ISession an einer anderen Stelle verwalten .

Aus der Dokumentation :

Von Zeit zu Zeit führt das ISessiondie SQL-Anweisungen aus, die zum Synchronisieren des Status der ADO.NET-Verbindung mit dem Status der im Speicher gespeicherten Objekte erforderlich sind. Dieser Vorgang, Flush, wird standardmäßig an den folgenden Punkten ausgeführt

  • von einigen Anrufungen von Find()oderEnumerable()
  • von NHibernate.ITransaction.Commit()
  • von ISession.Flush()

Die SQL-Anweisungen werden in der folgenden Reihenfolge ausgegeben

  1. Alle Entitätseinfügungen in derselben Reihenfolge, in der die entsprechenden Objekte gespeichert wurden ISession.Save()
  2. alle Entitätsaktualisierungen
  3. alle Löschungen der Sammlung
  4. Alle Löschungen, Aktualisierungen und Einfügungen von Sammlungselementen
  5. alle Sammlungseinfügungen
  6. Alle Entitätslöschungen, in derselben Reihenfolge wurden die entsprechenden Objekte mit gelöscht ISession.Delete()

(Eine Ausnahme besteht darin, dass Objekte, die die native ID-Generierung verwenden, beim Speichern eingefügt werden.)

Außer wenn Sie explizit sind Flush(), gibt es absolut keine Garantie dafür, wann die Sitzung die ADO.NET-Aufrufe ausführt, sondern nur die Reihenfolge, in der sie ausgeführt werden . NHibernate garantiert jedoch, dass die ISession.Find(..)Methoden niemals veraltete Daten zurückgeben. Sie werden auch nicht die falschen Daten zurückgeben.

Es ist möglich, das Standardverhalten so zu ändern, dass das Spülen weniger häufig auftritt. Die FlushModeKlasse definiert drei verschiedene Modi: Nur zum Festschreiben löschen (und nur, wenn die NHibernate- ITransactionAPI verwendet wird), automatisch mit der erläuterten Routine leeren oder niemals leeren, es Flush()sei denn, dies wird explizit aufgerufen. Der letzte Modus ist nützlich für lange laufende Arbeitseinheiten, bei denen ISessioneine lange Zeit offen gehalten und getrennt wird.

...

Siehe auch diesen Abschnitt :

Das Beenden einer Sitzung umfasst vier verschiedene Phasen:

  • Spülen Sie die Sitzung
  • Übernehmen Sie die Transaktion
  • Schließen Sie die Sitzung
  • Ausnahmen behandeln

Sitzung spülen

Wenn Sie zufällig die ITransactionAPI verwenden, müssen Sie sich über diesen Schritt keine Gedanken machen. Es wird implizit ausgeführt, wenn die Transaktion festgeschrieben wird. Andernfalls sollten Sie aufrufen, ISession.Flush()um sicherzustellen, dass alle Änderungen mit der Datenbank synchronisiert sind.

Festschreiben der Datenbanktransaktion

Wenn Sie die NHibernate ITransaction API verwenden, sieht dies folgendermaßen aus:

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

Wenn Sie ADO.NET-Transaktionen selbst verwalten, sollten Sie Commit()die ADO.NET-Transaktion manuell ausführen.

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

Wenn Sie sich entscheiden, Ihre Änderungen nicht zu übernehmen:

tx.Rollback();  // rollback the transaction

oder:

currentTransaction.Rollback();

Wenn Sie die Transaktion zurücksetzen, sollten Sie die aktuelle Sitzung sofort schließen und verwerfen, um sicherzustellen, dass der interne Status von NHibernate konsistent ist.

Die ISession schließen

Ein Aufruf zum ISession.Close()Markieren des Endes einer Sitzung. Die Hauptaussage von Close () ist, dass die ADO.NET-Verbindung von der Sitzung getrennt wird.

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

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

Wenn Sie Ihre eigene Verbindung bereitgestellt haben, wird Close()ein Verweis darauf zurückgegeben, sodass Sie sie manuell schließen oder an den Pool zurückgeben können. Andernfalls wird Close()es in den Pool zurückgegeben.

Matt Hinze
quelle
2
Für mich war diese Zeile der Schlüssel: "Die Hauptaussage von Close () ist, dass die ADO.NET-Verbindung von der Sitzung freigegeben wird." Wenn Sie ISession.Close () nicht aufrufen, werden Ihre Verbindungen gefüllt, bis Sie DB-Timeouts erhalten. : o
dave thieben
Wir: normalerweise: Sitzung öffnen session.BeginTransaction () work ... session.Transaction.Commit () session.BeginTransaction () work ... session.Transaction.Commit () session.BeginTransaction () work .. session.Transaction.Commit () Sitzung entsorgen.
Agile Jedi
Geniales Schreiben und +1 und so weiter - ich denke jedoch, dass eine Bearbeitung erforderlich sein könnte, da Sie oben "Niemals schließen" und später "Wenn Sie die Transaktion
zurücksetzen,
Kann die Reihenfolge der SQL-Anweisungen geändert werden? Ich meine, ich muss eine Aktualisierung für ein Entitätsobjekt durchführen und dann einfügen, da ich eine Einschränkung in der entsprechenden Tabelle habe.
Bob_saginowski
14

Ab NHibernate 2.0 sind Transaktionen für DB-Vorgänge erforderlich. Daher ITransaction.Commit()übernimmt der Anruf alle erforderlichen Spülungen. Wenn Sie aus irgendeinem Grund keine NHibernate-Transaktionen verwenden, wird die Sitzung nicht automatisch gelöscht.

Sean Carpenter
quelle
1

Von Zeit zu Zeit führt die ISession die SQL-Anweisungen aus, die zum Synchronisieren des Status der ADO.NET-Verbindung mit dem Status der im Speicher gespeicherten Objekte erforderlich sind.

Und immer benutzen

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

Nachdem die Änderungen festgeschrieben wurden, verwenden wir transaction.Commit (), um sie in der Datenbank zu speichern.

Gander
quelle
0

Hier sind zwei Beispiele für meinen Code, bei dem er ohne session fehlschlagen würde.Flush ():

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

Am Ende sehen Sie einen Codeabschnitt, in dem ich die Identitätseinfügung aktiviert, die Entität gespeichert, dann gelöscht und die Identitätseinfügung deaktiviert habe. Ohne diesen Flush schien es, die Identitätseinfügung ein- und auszuschalten und dann die Entität zu speichern.

Die Verwendung von Flush () gab mir mehr Kontrolle darüber, was los war.

Hier ist ein weiteres Beispiel:

Senden einer NServiceBus-Nachricht in TransactionScope

Ich verstehe nicht ganz warum, aber Flush () hat verhindert, dass mein Fehler auftritt.

Paul T. Davies
quelle