wake-up-neo.net

Transaktions-Rollback für Entity Framework 6

Mit EF6 haben Sie eine neue Transaktion, die wie folgt verwendet werden kann:

using (var context = new PostEntityContainer())
        {
            using (var dbcxtransaction = context.Database.BeginTransaction())
            {
                try
                {
                    PostInformation NewPost = new PostInformation()
                    {
                        PostId = 101,
                        Content = "This is my first Post related to Entity Model",
                        Title = "Transaction in EF 6 beta"
                    };
                    context.Post_Details.Add(NewPost);
                    context.SaveChanges();
                    PostAdditionalInformation PostInformation = new PostAdditionalInformation()
                    {
                        PostId = (101),
                        PostName = "Working With Transaction in Entity Model 6 Beta Version"
                    };

                    context.PostAddtional_Details.Add(PostInformation);
                    context.SaveChanges();

                    dbcxtransaction.Commit();
                }
                catch
                {
                    dbcxtransaction.Rollback();
                }
            }
        }

Ist ein Rollback tatsächlich erforderlich, wenn sich die Dinge seitwärts entwickeln? Ich bin neugierig, weil in der Commit-Beschreibung steht: "Commit der zugrunde liegenden Filialtransaktion."

In der Rollback-Beschreibung heißt es hingegen: "Rollback der zugrunde liegenden Filialtransaktion."

Das macht mich neugierig, denn es sieht für mich so aus, als würden die zuvor ausgeführten Befehle nicht gespeichert, wenn Commit nicht aufgerufen wird (was mir logisch erscheint). Aber wenn dies der Fall ist, warum sollte die Rollback-Funktion aufgerufen werden? In EF5 habe ich TransactionScope verwendet, das keine Rollback-Funktion (nur eine vollständige) hatte, was mir logisch erschien. Aus MS DTC-Gründen kann ich das TransactionScope nicht mehr verwenden, aber ich kann auch keinen Try-Catch wie im obigen Beispiel verwenden (d. H. Ich benötige nur das Commit).

72
The Cookies Dog

Sie müssen Rollback nicht manuell aufrufen, da Sie die Anweisung using verwenden.

DbContextTransaction.Dispose Methode wird am Ende des using Blocks aufgerufen. Die Transaktion wird automatisch zurückgesetzt, wenn die Transaktion nicht erfolgreich festgeschrieben wurde (keine aufgerufenen oder aufgetretenen Ausnahmen). Es folgt der Quellcode von SqlInternalTransaction.Dispose Methode (DbContextTransaction.Dispose wird bei Verwendung des SqlServer-Providers endlich an ihn delegieren):

private void Dispose(bool disposing)
{
    // ...
    if (disposing && this._innerConnection != null)
    {
        this._disposing = true;
        this.Rollback();
    }
}

Sie sehen, es prüft, ob _innerConnection ist nicht null, andernfalls wird die Transaktion zurückgesetzt (wenn festgeschrieben, _innerConnection wird null sein). Mal sehen, was Commit macht:

internal void Commit() 
{
    // Ignore many details here...

    this._innerConnection.ExecuteTransaction(...);

    if (!this.IsZombied && !this._innerConnection.IsYukonOrNewer)
    {
        // Zombie() method will set _innerConnection to null
        this.Zombie();
    }
    else
    {
        this.ZombieParent();
    }

    // Ignore many details here...
}

internal void Zombie()
{
    this.ZombieParent();

    SqlInternalConnection innerConnection = this._innerConnection;

    // Set the _innerConnection to null
    this._innerConnection = null;

    if (innerConnection != null)
    {
        innerConnection.DisconnectTransaction(this);
    }
}
105
Mouhong Lin

Solange Sie SQL Server immer mit EF verwenden, müssen Sie den catch nicht explizit verwenden, um die Rollback-Methode aufzurufen. Das automatische Zurücksetzen des using-Blocks bei Ausnahmen funktioniert immer.

Wenn Sie jedoch aus der Sicht von Entity Framework darüber nachdenken, können Sie sehen, warum in allen Beispielen der explizite Aufruf zum Zurücksetzen der Transaktion verwendet wird. Für die EF ist der Datenbankanbieter beliebig und steckbar, und der Anbieter kann durch MySQL oder eine andere Datenbank mit einer EF-Anbieterimplementierung ersetzt werden. Aus Sicht von EF kann daher nicht garantiert werden, dass der Anbieter die veräußerte Transaktion automatisch zurücksetzt, da der EF nicht über die Implementierung des Datenbankanbieters informiert ist.

Daher wird in der EF-Dokumentation als bewährte Methode ausdrücklich ein Rollback empfohlen - nur für den Fall, dass Sie eines Tages den Anbieter zu einer Implementierung wechseln, bei der kein automatisches Rollback durchgeführt wird.

Meiner Meinung nach wird jeder gute und gut geschriebene Anbieter die Transaktion automatisch zurücksetzen, so dass der zusätzliche Aufwand, alles innerhalb des using-Blocks mit einem Try-Catch-Rollback zu verpacken, übertrieben ist.

21
Rwb
  1. Da Sie einen 'using'-Block geschrieben haben, um die Transaktion zu instanziieren, müssen Sie die Rollback-Funktion nicht explizit erwähnen, da sie zum Zeitpunkt der Verfügung automatisch zurückgesetzt wird (es sei denn, sie wurde festgeschrieben).
  2. Wenn Sie es jedoch ohne using-Block instanziieren, ist es in diesem Fall unerlässlich, die Transaktion im Falle einer Ausnahme (genau in einem catch-Block) zurückzusetzen, und dies auch mit einer Nullprüfung für einen robusteren Code. Die Arbeitsweise von BeginTransaction unterscheidet sich vom Transaktionsbereich (der nur eine vollständige Funktion benötigt, wenn alle Vorgänge erfolgreich abgeschlossen wurden). Stattdessen ähnelt es der Arbeit von SQL-Transaktionen.
4
roopaliv