首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Entity Framework 6事务回滚

Entity Framework 6事务回滚
EN

Stack Overflow用户
提问于 2014-03-19 01:18:49
回答 3查看 70.5K关注 0票数 86

有了EF6,你就有了一个新的事务,它可以像这样使用:

代码语言:javascript
复制
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,之前执行的命令将不会被存储(这对我来说似乎是合乎逻辑的)。但是如果是这样,那么调用回滚函数的原因是什么呢?在EF5中,我使用的是TransactionScope,它没有回滚功能(只有一个完整的回滚功能),这对我来说似乎是合乎逻辑的。由于MS的原因,我不能再使用TransactionScope,但我也不能像上面的例子那样使用try catch (即,我只需要提交)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-07-06 11:47:27

您不需要手动调用Rollback,因为您使用的是using语句。

using块的末尾将调用DbContextTransaction.Dispose方法。如果事务未成功提交(未调用或遇到异常),它将自动回滚事务。下面是SqlInternalTransaction.Dispose方法的源码(使用SqlServer provider时,DbContextTransaction.Dispose最终会委托给它):

代码语言:javascript
复制
private void Dispose(bool disposing)
{
    // ...
    if (disposing && this._innerConnection != null)
    {
        this._disposing = true;
        this.Rollback();
    }
}

您看,它检查_innerConnection是否不为null,如果不是,则回滚事务(如果已提交,则_innerConnection将为null)。让我们看看Commit做了什么:

代码语言:javascript
复制
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);
    }
}
票数 126
EN

Stack Overflow用户

发布于 2015-03-07 21:44:52

只要您始终将SQL Server与EF一起使用,就不需要显式地使用catch来调用Rollback方法。允许using块在任何异常上自动回滚将始终有效。

但是,当您从实体框架的角度考虑它时,您就会明白为什么所有示例都使用显式调用来回滚事务。对于EF来说,数据库提供程序是任意的和可插拔的,提供程序可以用MySQL或任何其他具有EF提供程序实现的数据库替换。因此,从EF的角度来看,不能保证提供程序将自动回滚已处置的事务,因为EF不知道数据库提供程序的实现。

因此,作为最佳实践,EF文档建议您显式回滚--以防有一天您将提供者更改为不会在dispose上自动回滚的实现。

在我看来,任何编写良好的提供程序都会自动回滚dispose中的事务,因此使用try-catch-rollback包装using块中的所有内容的额外工作是多余的。

票数 30
EN

Stack Overflow用户

发布于 2014-07-09 18:06:50

  1. 由于您已经编写了一个'using‘块来实例化事务,因此不需要显式地提到回滚函数,因为它将在释放时自动回滚(除非它已提交)。

块,但如果您不使用using块实例化它,在这种情况下,在出现异常的情况下(精确地在

  1. 块中)回滚事务是必不可少的,并且使用null检查也是为了获得更健壮的代码。BeginTransaction的工作原理与事务作用域不同(如果所有操作都成功完成,则事务作用域只需要一个完整的功能)。相反,它类似于Sql事务的工作方式。
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22486489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档