0

在自定义工作单元中可能有多个 DbContext 的情况下,EF5 是否会管理所有事务要求,或者下面的代码是否仍然有效/需要?如果没有,代码可以减少多远并且仍然提供相同的功能?

public void SaveAllChanges()
{
    var transactions = new List<DbTransaction>();

    foreach (var context in this.contexts
        .Where(context => context != null)
        .Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext))
    {
        context.Connection.Open();

        var databaseTransaction = context.Connection.BeginTransaction();

        transactions.Add(databaseTransaction);

        try
        {
            context.SaveChanges();
        }
        catch
        {
            foreach (var transaction in transactions)
            {
                try
                {
                    transaction.Rollback();
                }
                finally
                {
                    databaseTransaction.Dispose();
                }
            }

            transactions.Clear();

            throw;
        }
    }

    try
    {
        foreach (var transaction in transactions)
        {
            transaction.Commit();
        }
    }
    finally
    {
        foreach (var transaction in transactions)
        {
            transaction.Dispose();
        }

        transactions.Clear();

        foreach (var context in this.contexts
            .Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext)
            .Where(context => context.Connection.State != ConnectionState.Closed))
        {
            context.Connection.Close();
        }
    }
}

假设 SQL Server 2008 及更高版本。

4

1 回答 1

0

在使用多个上下文时,您必须自己处理事务,但您的代码是错误的。如果您的任何事务在提交期间失败,您可以提交部分事务并回滚部分事务。

唯一有效的方法是手动使用TransactionScope管理EF 的连接或使用分布式事务:

var objectContexts = this.contexts
                         .Where(context => context != null)
                         .Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext))
                         .ToArray();

var transactionOptions = new TransactionOptions { 
    IsolationLevel = IsolationLevel.ReadCommitted 
};
using (var scope = new TransactionScope(TransactionScopeOption.Required,
                                        transactionOptions)) {
   Array.ForEach(objectContext, 
                 o => o.SaveChanges(SaveOptions.DetectChangesBeforeSave));
   scope.Complete();
}

Array.ForEach(objectContext, o => o.AcceptAllChanges());

这里描述了为什么 AcceptAllChanges 很重要。

于 2012-09-17T08:56:56.070 回答