NHibernate: Kann Session.Flush () vor dem Commit einer Transaktion aufgerufen werden?

8

Ich muss zwei Operationen innerhalb einer NHibernate-Arbeitseinheit ausführen: eine transaktionale (eine Entitätsspeicherung) und eine nichttransaktionale.

Da die nichttransaktionale Operation nicht zurückgesetzt werden kann, wenn ich die Entität vor speichere, die die nichttransaktionale Operation ausführt (und schließlich die Transaktion festschreibt), erhalte ich immer noch ein Transaktionsverhalten:

  • Die Operationen werden nur ausgeführt, wenn die beiden Unteroperationen erfolgreich ausgeführt werden;
  • Wenn das Speichern der Entität fehlschlägt, wird die nichttransaktionale Operation nicht ausgeführt;
  • Wenn die Nichttransaktion fehlschlägt, wird die Entitätsspeicherung zurückgesetzt.

Das Problem: Mit einem Code wie dem folgenden wird NHibernate die eigentliche SQL-Einfügung erst beim Aufruf von transaction.Commit () ausführen (der intern session.Flush () aufruft):

%Vor%

Wenn der Sql-Insert fehlschlägt, ist es mit einem Code wie diesem zu spät: NotTransactionalOperation wurde ausgeführt. Um das eigentliche SQL-Insert vor dem Ausführen von NotTransactionalOperation ausführen zu können, muss ich session.Flush () direkt vor der Session aufrufen.Save ():

%Vor%

Der Code funktioniert, aber ... ist es eine bewährte Methode, session.Flush () vor dem Commit der Transaktion aufzurufen? Wenn nicht, gibt es bessere Möglichkeiten, um das gleiche Ergebnis zu erzielen?

    
Notoriousxl 28.03.2011, 21:13
quelle

2 Antworten

3

Flushing bedeutet, dass NHibernate sicherstellen wird, dass alle Änderungen in der DB beibehalten werden. Das heißt, es wird sichergestellt, dass alle notwendigen SQL-Anweisungen ausgeführt werden. Wenn die Transaktion fehlschlägt und daher zurückgesetzt wird, werden alle diese Änderungen rückgängig gemacht. Daher sehe ich kein Problem darin (Sie müssen jedoch beachten, dass Ihre Entität möglicherweise nicht in einem gültigen Status ist, da die Transaktion fehlgeschlagen ist).

Aber ... ich sehe das Problem eigentlich nicht: Wenn das nicht transaktionale Verfahren fehlschlägt, was ist das Problem? Da die Prozedur nicht transaktional ist, hat sie keinen Einfluss auf die Informationen, die von der Datenbank gespeichert werden. Oder, was macht dieser Code?

Wenn es nicht transaktional ist, warum können Sie es nicht außerhalb Ihrer Arbeitseinheit tun?

Wenn das Speichern fehlschlägt, werde ich sicherstellen, dass nicht nur die Transaktion zurückgesetzt wird, sondern die Ausnahme auch auf den Stack geworfen wird, bis sie auf einen Fehler-Handler stößt Nicht-Transaktionscode wird ebenfalls nicht ausgeführt:

%Vor%     
Frederik Gheysels 28.03.2011, 21:22
quelle
1

Es ist ungewöhnlich, aber wenn Sie etwas außerhalb der Arbeitseinheit tun möchten, das von etwas abhängt, das im Inneren erledigt wird, ist es absolut gültig. Die Frage wird dann jedoch: Warum wird die Operation außerhalb der Arbeitseinheit ausgeführt, wenn sie von etwas im Inneren abhängt? Wenn es vollständig auftragsabhängig ist, sollten Sie eine Flush-Operation AND Commit in Erwägung ziehen, bevor Sie die nicht transaktionale Operation ausführen. Wenn die Nicht-Trans-Operation feststellt, ob die gesamte Sache committen wird (zum Beispiel, vielleicht wirft sie eine Ausnahme auf), sollte sie Teil der Arbeitseinheit sein.

Die Nicht-Trans-Option sollte außerdem wahrscheinlich nicht von den Daten in der DB abhängen, außer sie hängt vom Code der Datenschicht ab, wie Trigger (obwohl ich Trigger mag, sollten sie generell aus verschiedenen Gründen vermieden werden, nicht zuletzt die Tendenz, solche sicheren Operationen zu verwickeln. Sie sollten Ihre Geschäftslogik im Allgemeinen in Ihrer Anwendungsebene behalten, außer als letzte Option. Wenn das Objekt in einer Sitzung gespeichert wurde, sind die Daten dort verfügbar, wo diese Sitzung ist, und diese Sitzung sollte so breit wie nötig sein (oder eine gemeinsam genutzte "Elternsitzung" mit Kindern in Betracht ziehen, die Zugriff auf das Elternobjekt haben) alle Zeiten).

    
KeithS 28.03.2011 21:21
quelle