4

ジェネリックを使用してエンティティのリポジトリを取得するために、次のUnitOfWorkクラスを使用しています。

public class UnitOfWork : IUnitOfWork
{
  private readonly EfDbContext _context;

  public UnitOfWork()
  {
    _context = new EfDbContext();
  }

  public IRepository<T> RepositoryFor<T>() where T : Entity
  {
    return new Repository<T>(_context);
  }

  public void Save()
  {
    _context.SaveChanges();
  }
}

ただし、1 つのエンティティに対して UnitOfWork を個別にインスタンス化する 2 つの別個のクラスがあるという問題に遭遇しました。つまり、そのエンティティに対して 2 つのリポジトリが作成されます。これにより、エンティティを保存しようとすると、エンティティ フレームワークで「エンティティ オブジェクトを IEntityChangeTracker の複数のインスタンスで参照することはできません」というエラーがスローされるという問題が発生します。

リポジトリがプライベート フィールドに格納され、存在する場合は再利用されるか、null の場合は作成される「作業単位クラスの作成」セクションの下で、Tom Dykstra によるこの投稿で説明されているように、UOW パターンにもっと厳密に従う必要があると考えています。これに関して私が抱えている問題は、UOW で引き続きジェネリックを使用Repository<T>することであり、コード内のすべてのエンティティ タイプに対してプライベート リポジトリ フィールドを宣言する必要はありません。

特定のタイプのリポジトリがすでにインスタンス化されているという事実を保存し、その新しいインスタンスを作成する代わりにそれを再利用するにはどうすればよいでしょうか?

--- 編集: これが修正です ---

Ninject を使用して、次のように指定して、リポジトリと UOW の両方のインスタンスを 1 つだけインスタンス化するようにバインディングを調整しました。InRequestScope

kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
//kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); // Removed based on comment below
kernel.Bind(typeof(EfDbContext)).ToSelf().InRequestScope();
4

2 に答える 2

3

問題は複数のリポジトリではなく、複数のDbContextインスタンスにあります。EF は、同じエンティティ インスタンスを一度に複数のコンテキストに追加できないことを示しています。したがって、リポジトリを共有しても役に立ちません。さらに、シングルトン リポジトリを共有する複数の UoW を持つことは地獄への道です。同時実行性 (EF はスレッドセーフではありません)、状態などを処理するのは非常に困難です。

この問題を解決するには、次のいずれかを行う必要があります。

  1. DbContext作業単位を共有して、単一のビジネス オペレーション全体で UoW (および) の同じインスタンスを使用する
  2. 別の UoW に追加する前に、エンティティ インスタンスのコピーを作成します。

選択は、特定の状況によって異なります。

于 2012-04-18T04:02:20.500 に答える