NHibernate ISession Flush:Wo und wann sollte man es verwenden und warum?
-
09-06-2019 - |
Frage
Eines der Dinge, die mich völlig verwirren, ist die Verwendung von session.Flush
,in Verbindung mit session.Commit
, Und session.Close
.
Manchmal session.Close
funktioniert, z. B. werden alle Änderungen übernommen, die ich benötige.Ich weiß, dass ich Commit verwenden muss, wenn ich eine Transaktion oder eine Arbeitseinheit mit mehreren Erstellungs-/Aktualisierungs-/Löschvorgängen habe, damit ich bei Auftreten eines Fehlers ein Rollback durchführen kann.
Aber manchmal verwirrt mich die Logik dahinter wirklich session.Flush
.Ich habe Beispiele gesehen, bei denen Sie eine haben session.SaveOrUpdate()
gefolgt von einem Flush, aber wenn ich Flush entferne, funktioniert es trotzdem einwandfrei.Manchmal stoße ich auf Fehler in der Flush-Anweisung, die besagen, dass die Sitzung abgelaufen ist, und durch das Entfernen wurde sichergestellt, dass dieser Fehler nicht auftritt.
Hat jemand eine gute Richtlinie, wo und wann man einen Flush verwenden sollte?Ich habe mir dazu die NHibernate-Dokumentation angesehen, kann aber immer noch keine eindeutige Antwort finden.
Lösung
Knapp:
- Verwenden Sie immer Transaktionen
- Nicht verwenden
Close()
, wickeln Sie Ihre Anrufe stattdessen auf einISession
in einemusing
Aussage bzw Verwalten Sie den Lebenszyklus Ihrer ISession woanders.
Aus die Dokumentation:
Von Zeit zu Zeit
ISession
führt die erforderlichen SQL-Anweisungen aus, um den Status der ADO.NET-Verbindung mit dem Status der im Speicher gehaltenen Objekte zu synchronisieren.Dieser Vorgang, Flush, findet standardmäßig an den folgenden Punkten statt
- aus einigen Aufrufen von
Find()
oderEnumerable()
- aus
NHibernate.ITransaction.Commit()
- aus
ISession.Flush()
Die SQL-Anweisungen werden in der folgenden Reihenfolge ausgegeben
- alle Entitätseinfügungen in derselben Reihenfolge, in der die entsprechenden Objekte gespeichert wurden
ISession.Save()
- alle Entitätsaktualisierungen
- alle Sammlungslöschungen
- alle Löschungen, Aktualisierungen und Einfügungen von Sammlungselementen
- alle Sammlungseinfügungen
- Alle Entitätslöschungen in derselben Reihenfolge, in der die entsprechenden Objekte gelöscht wurden
ISession.Delete()
(Eine Ausnahme besteht darin, dass Objekte mit nativer ID-Generierung beim Speichern eingefügt werden.)
Außer wenn Sie dies ausdrücklich tun
Flush()
, gibt es keinerlei Garantien dafür, wann die Sitzung die ADO.NET-Aufrufe ausführt, sondern nur für die Reihenfolge, in der sie ausgeführt werden.NHibernate garantiert jedoch, dass dieISession.Find(..)
Methoden geben niemals veraltete Daten zurück;Sie werden auch nicht die falschen Daten zurückgeben.Es ist möglich, das Standardverhalten so zu ändern, dass die Spülung seltener erfolgt.Der
FlushMode
Die Klasse definiert drei verschiedene Modi:nur zum Commit-Zeitpunkt leeren (und nur, wenn die NHibernateITransaction
API verwendet wird), automatisch mit der erläuterten Routine leeren oder nie leeren, es sei dennFlush()
wird explizit aufgerufen.Der letzte Modus ist nützlich für Arbeitseinheiten mit langer Laufzeit, bei denen einISession
wird für längere Zeit offen gehalten und abgeklemmt.
...
Siehe auch diese Abteilung:
Das Beenden einer Sitzung umfasst vier verschiedene Phasen:
- Spülen Sie die Sitzung
- die Transaktion festschreiben
- Schließen Sie die Sitzung
- Ausnahmen behandeln
Leeren der Sitzung
Wenn Sie zufällig das verwenden
ITransaction
API, Sie müssen sich über diesen Schritt keine Gedanken machen.Dies wird implizit ausgeführt, wenn die Transaktion festgeschrieben wird.Ansonsten solltest du anrufenISession.Flush()
um sicherzustellen, dass alle Änderungen mit der Datenbank synchronisiert werden.Festschreiben der Datenbanktransaktion
Wenn Sie die NHibernate ITransaction API verwenden, sieht dies so aus:
tx.Commit(); // flush the session and commit the transaction
Wenn Sie ADO.NET-Transaktionen selbst verwalten, sollten Sie dies manuell tun
Commit()
die ADO.NET-Transaktion.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.
Schließen der ISession
Ein Aufruf an
ISession.Close()
markiert das Ende einer Sitzung.Die Hauptauswirkung von Close() besteht darin, dass die ADO.NET-Verbindung von der Sitzung getrennt wird.tx.Commit(); sess.Close(); sess.Flush(); currentTransaction.Commit(); sess.Close();
Wenn Sie Ihren eigenen Anschluss bereitgestellt haben,
Close()
gibt einen Verweis darauf zurück, sodass Sie es manuell schließen oder an den Pool zurückgeben können.AnsonstenClose()
gibt es an den Pool zurück.
Andere Tipps
Ab NHibernate 2.0 sind Transaktionen für DB-Vorgänge erforderlich.deshalb, die ITransaction.Commit()
Der Anruf übernimmt die erforderliche Spülung.Wenn Sie aus irgendeinem Grund keine NHibernate-Transaktionen verwenden, erfolgt kein automatisches Leeren der Sitzung.
Von Zeit zu Zeit führt die ISession die erforderlichen SQL-Anweisungen aus, um den Status der ADO.NET-Verbindung mit dem Status der im Speicher gehaltenen Objekte zu synchronisieren.
Und immer verwenden
using (var transaction = session.BeginTransaction())
{
transaction.Commit();
}
Nachdem die Änderungen festgeschrieben wurden, verwenden wir zum Speichern dieser Änderungen in der Datenbank „transaction.Commit();“
Hier sind zwei Beispiele meines Codes, bei dem er ohne session.Flush() fehlschlagen würde:
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 speichere, sie dann leere und dann die Identitätseinfügung ausschalte.Ohne diesen Flush schien es, als würde die Identitätseinfügung ein- und ausgeschaltet und dann die Entität gespeichert.
Die Verwendung von Flush() gab mir mehr Kontrolle darüber, was vor sich ging.
Hier ist ein weiteres Beispiel:
Senden einer NServiceBus-Nachricht innerhalb von TransactionScope
Ich verstehe nicht ganz, warum das so ist, aber Flush() hat meinen Fehler verhindert.