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

SQLServer2008以降を想定します。

4

1 に答える 1

0

複数のコンテキストで作業する場合は、トランザクションを自分で処理する必要がありますが、コードが間違っています。コミット中にトランザクションのいずれかが失敗した場合、トランザクションの一部をコミットし、トランザクションの一部をロールバックすることができます。

唯一の有効なアプローチは、EFの接続を手動で使用して管理するTransactionScopeか、分散トランザクションを使用することです。

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 に答える