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

时间:2012-10-09 23:40:01

标签: entity-framework sql-server-2012 transactionscope entity-framework-5 msdtc

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

我尝试过:

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

    db.SaveChanges();

    // Do something else

    db.SaveChanges();

    tramsaction.Complete();
}

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

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

当然必须采用更轻量级的方式(理想情况下没有MSDTC)?!

4 个答案:

答案 0 :(得分:13)

我知道它的答案很晚,但我觉得分享很有用。

现在在 EF6 中,使用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();
        }
    }
}

有关详细信息,请查看this

再次进入EF6 Onwards

答案 1 :(得分: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();
} 

答案 2 :(得分: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();
        }

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

答案 3 :(得分:1)

对于上面选择的最终答案,有一个错字。更正如下:

objectContext.Connection.Open();

另外,需要为System.Data.Entity.Infrastructure和System.Transactions添加引用