簡體   English   中英

實體框架6事務回滾

[英]Entity Framework 6 transaction rollback

使用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,先前執行的命令將不會被存儲(對我來說這是合乎邏輯的)。 但是如果是這種情況,調用Rollback函數的原因是什么? 在EF5中,我使用了TransactionScope,它沒有回滾功能(只有完整功能),這對我來說似乎很合理。 由於MS DTC的原因,我不能再使用TransactionScope,但是也不能像上面的示例那樣使用try catch(即,我只需要Commit)。

您不需要手動調用Rollback ,因為您正在使用using語句。

DbContextTransaction.Dispose方法將在using塊的末尾調用。 如果未成功提交事務(未調用或遇到異常),它將自動回滾事務。 以下是SqlInternalTransaction.Dispose方法的源代碼(使用SqlServer提供程序時, DbContextTransaction.Dispose將最終委托給它):

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

只要您始終將SQL Server與EF一起使用,就無需顯式使用catch來調用Rollback方法。 允許using塊自動回滾任何異常將始終有效。

但是,從實體框架的角度考慮它時,您可以看到為什么所有示例都使用顯式調用來回滾事務。 對於EF,數據庫提供程序是任意的且可插入的,並且可以使用MySQL或具有EF提供程序實現的任何其他數據庫替換該提供程序。 因此,從EF的角度來看,由於EF不知道數據庫提供程序的實現,因此不能保證提供程序將自動回滾已處置的事務。

因此,作為最佳實踐,EF文檔建議您顯式回滾-以防萬一有一天您將提供程序更改為在處置時不會自動回滾的實現。

在我看來,任何優秀且編寫良好的提供程序都將自動在Dispose中回滾事務,因此用try-catch-rollback將所有內容包裝在using塊內的額外努力是過大的。

  1. 由於您已經編寫了一個“使用”塊來實例化事務,因此您無需顯式提及Rollback函數,因為它將在處置時自動回滾(除非已提交)。
  2. 但是,如果您在不使用using塊的情況下實例化它,則在這種情況下,必須在發生異常(准確地在catch塊中)的情況下回滾事務,並且對於空健的代碼也必須進行空檢查。 BeginTransaction的工作方式不同於事務范圍(如果成功完成所有操作,則只需要一個完整的功能)。 相反,它類似於Sql事務的工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM