16

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

我试着做:

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

    db.SaveChanges();

    // Do something else

    db.SaveChanges();

    tramsaction.Complete();
}

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

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

当然必须有一种更轻量级的方法来做到这一点(最好没有 MSDTC)?!

4

3 回答 3

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

有关更多信息,请查看

又是在 EF6 以后

于 2014-04-26T09:24:02.170 回答
8

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

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

try {
    //Open Connection
    objectContext.Connection.Open();

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

        db.SaveChanges();

        // Do something else

        db.SaveChanges();

        transaction.Complete();
    }
} finally {
    //Close connection after commit
    objectContext.Connection.Close();
} 
于 2012-10-10T09:26:01.660 回答
7

通过按原样调用 SaveChanges() 会导致数据持久保存到数据库中,并且 EF 会忘记它刚刚所做的更改。

诀窍是使用 SaveChanges(false) 以便将更改持久保存到数据库中,但 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();
        }

PS 只要您在事务范围内打开了多个连接,它就会升级为 DTC。

于 2013-02-26T10:52:08.843 回答