EF:如何在交易中两次调用SaveChanges?

Gar*_*ill 15 msdtc entity-framework transactionscope sql-server-2012 entity-framework-5

使用Entity Framework(在我的例子中是代码),我有一个操作,需要我调用SaveChanges来更新DB中的一个对象,然后再次SaveChanges来更新另一个对象.(我需要第一个SaveChanges来解决EF无法确定首先更新哪个对象的问题).

我试过做:

using (var transaction = new TransactionScope())
{
    // Do something

    db.SaveChanges();

    // Do something else

    db.SaveChanges();

    tramsaction.Complete();
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我在第二次SaveChanges调用时遇到异常,说"底层提供程序在打开时失败".内部异常表示我的机器上未启用MSDTC.

现在,我在其他地方看到了描述如何启用MSDTC的帖子,但似乎我还需要启用网络访问等.这听起来像是完全矫枉过正,因为没有涉及其他数据库,更不用说其他服务器了.我不想做一些会使我的整个应用程序不那么安全(或更慢)的东西.

当然必须有一个更轻量级的方法(理想情况下没有MSDTC)?!

Wah*_*tar 13

我知道这是一个迟到的答案,但我发现分享很有用.

现在,在EF6它更容易使用到acheeve此dbContext.Database.BeginTransaction()

像这样 :

using (var context = new BloggingContext())
{
    using (var dbContextTransaction = context.Database.BeginTransaction())
    {
        try
        {
            // do your changes
            context.SaveChanges();

            // do another changes
            context.SaveChanges();

            dbContextTransaction.Commit();
        }
        catch (Exception)
        {
            dbContextTransaction.Rollback();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看此内容

再次它在EF6 Onwards


Lad*_*nka 8

它可能是由您的事务中使用的两个不同连接引起的.尝试手动控制操作的连接:

var objectContext = ((IObjectContextAdapter)db).ObjectContext;

try {
    object.Context.Connection.Open();
    using (var transaction = new TransactionScope()) {
        // Do something

        db.SaveChanges();

        // Do something else

        db.SaveChanges();

        transaction.Complete();
    }
} finally {
    objectContext.Connection.Close();
} 
Run Code Online (Sandbox Code Playgroud)


Pau*_*hra 7

通过调用SaveChanges(),可以将数据持久保存到数据库,而EF则忘记它刚才所做的更改.

诀窍是使用SaveChanges(false),以便更改持久保存到DB,但EF不会忘记它所做的更改,从而使记录/重试成为可能.

        var scope = new TransactionScope(
            TransactionScopeOption.RequiresNew,
            new TransactionOptions() { IsolationLevel = IsolationLevel.Serializable }
        );

        using (scope)
        {
            Entities context1 = new Entities();
            // Do Stuff
            context1.SaveChanges(false);

            Entities context2 = new Entities();
            // Do Stuff
            context2.SaveChanges(false);

            scope.Complete();
            context1.AcceptAllChanges();
            context2.AcceptAllChanges();
        }
Run Code Online (Sandbox Code Playgroud)

PS只要在transactioncope中打开多个连接,它就会升级到DTC.