1

私のプロジェクトには古い ObjectContext といくつかの新しい DbContext があります (つまり、さまざまな目的のための BoundedContext です)。いくつかの変更を 1 回のトランザクションでコミットする必要がある場合があります。場合によっては、ObjectContext と DbContext からのデータを保持する必要があります。EF 5.0 では、MSDC を回避するためにいくつかのラッパーを作成します

public class ContextUnitOfWork
{
    List<IContext> ContextList;
    public ContextUnitOfWork()
    {
        ContextList = new List<IContext>(); 
    }
    public void RegisterContext(IContext Context)
    {
        ContextList.Add(Context);
    }
    public bool IsDisposed
    {
        get
        {
            return ContextList.Any(x => x.IsDisposed);
        }
    }
    public bool HasChangedEntities
    {
        get
        {
            return ContextList.Any(x => x.HasChangedEntities);
        }
    }
    public void Commit()
    {
        bool HasDbContext = ContextList.OfType<System.Data.Entity.DbContext>().Any();
        try
        {
            if (HasDbContext)
            {
                ContextList.ForEach(x =>
                {

                    if (x is System.Data.Entity.DbContext)
                    {
                        (x as System.Data.Entity.DbContext).Database.Connection.Open();
                    }
                    else if (x is System.Data.Objects.ObjectContext)
                    {
                        ((System.Data.Objects.ObjectContext)x).Connection.Open();
                    }

                });
            }

            using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required,
    new System.Transactions.TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
            {
                ContextList.ForEach(x => x.Commit());
                scope.Complete();
            }
        }
        catch (System.Data.UpdateException uex)
        {
            var ErrorList = uex.StateEntries.Select(x => x.Entity).ToList(); 
        }
        finally
        {
            if (HasDbContext)
            {
                ContextList.ForEach(x =>
                {
                    if (x is System.Data.Entity.DbContext)
                    {
                        (x as System.Data.Entity.DbContext).Database.Connection.Close();
                    }
                    else if (x is System.Data.Objects.ObjectContext)
                    {
                        ((System.Data.Objects.ObjectContext)x).Connection.Close();
                    }
                });
            };

        }
    }
}

しかし、EntityFramework 6.0.1 では機能しません。ObjectContext は正常にコミットされますが、DbContext が SaveChanges() を呼び出すと、タイプEntityExceptionの Exception がテキスト「The 基本プロバイダーが EnlistTransaction で失敗しました。」また、Inner Expection には、{"分散トランザクション マネージャー (MSDTC) のネットワーク アクセスが無効になっています。コンポーネント サービス管理ツールを使用して、MSDTC のセキュリティ構成でネットワーク アクセスの DTC を有効にしてください。 "}

1 つのトランザクションでコンテキストをコミットし、MDTC 例外を回避するためのアイデアはありますか?

4

1 に答える 1

2

同じタイプの複数のコンテキストであっても非常にトリッキーなローカル トランザクションですべてを実行しようとしています。これは、同じローカル トランザクションで複数の接続を開くことができないためです。また、前のコンテキストがまだ生きている場合、次のコンテキストのために新しい接続が開かれることがよくあります。これにより、ローカル トランザクションの分散トランザクションへの昇格がトリガーされます。

EF での私の経験では、接続文字列 (エンティティ接続文字列内の通常の接続文字列) が完全に同一である場合にのみ、現在の接続を再利用します。単一の違いがある場合、トランザクションは分散トランザクションに昇格します。これはシステムで有効にする必要がありますが、あなたの場合はそうではありません。

また、すでにクエリを実行していて、そのクエリからの結果を読み込んでいる場合、同時に別のクエリを開始すると (もちろん) 別の接続が必要になるため、ローカル トランザクションは分散トランザクションに昇格します。 .

接続文字列が同一かどうかを確認できますか? ただし、現在の接続が再利用された場合でも、私はまだ驚かれることでしょう。

于 2013-10-23T09:05:31.113 に答える