1. ホーム
  2. c#

[解決済み] Entity Framework 6 トランザクションのロールバック

2023-05-02 18:05:44

質問

EF6では、新しいトランザクションがあり、次のように使用することができます。

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();
                }
            }
        }

物事が横道にそれたとき、ロールバックは実際に必要なのでしょうか?Commit の説明では、" Commits the underlying store transaction." と書かれているので、気になります。

一方、ロールバックの説明では、"基礎となるストア トランザクションをロールバックします."。

なぜなら、Commit が呼び出されないと、以前に実行されたコマンドは保存されないように見えるからです (これは論理的だと思います)。しかし、もしそうであれば、Rollback 関数を呼び出す理由は何でしょうか。EF5ではTransactionScopeを使いましたが、Rollback関数がなく(Completeのみ)、これは論理的だと思いました。MS DTCの理由のために、私はもうTransactionScopeを使用することはできませんが、私はまた、上記の例のようなトライキャッチを使用することはできません(すなわち、私はコミットだけが必要です)。

どのように解決するのですか?

を呼び出す必要はありません。 Rollback を手動で呼び出す必要はありません。 using ステートメントを使用しているためです。

DbContextTransaction.Dispose メソッドの末尾で呼び出されます。 using ブロックの最後で呼び出されます。そして、トランザクションが正常にコミットされなかった場合(呼び出されなかったり、例外が発生した場合)、自動的にロールバックされます。以下は SqlInternalTransaction.Dispose メソッド ( DbContextTransaction.Dispose は、SqlServer プロバイダを使用する場合、最終的にこれに委譲されます)。

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

ほら、これは _innerConnection が NULL でないなら、トランザクションをロールバックします (コミットされた場合。 _innerConnection はNULLになる)。それでは Commit が何をするか見てみましょう。

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);
    }
}