web-dev-qa-db-ja.com

リポジトリパターン、作業単位、Unityを使用したエンティティフレームワーク

この例この実装 から提供される組み合わせを使用して、個々のリポジトリからUnitOfWorkクラスを分離するソリューションを作成しようとしています。オープンクローズ原則。新しいリポジトリを追加するたびに、UnitOfWorkクラスを変更する必要があるためです。 UnityをIoCコンテナーとして使用して、依存関係を結び付けています。

私が抱えている問題は、Unityを使用してUnitOfWorkIDbContextとリポジトリ(IEmployeeRepositoryICustomerRepository)を自動的に接続すると、リポジトリが注入されることです。 UnitOfWorkの個別のインスタンスを使用しますが、これはもちろん目的を無効にします。リポジトリ間でコンテキストを共有する必要がありますが、このパズルのピースが欠けているようです。現時点では(サービスレイヤーを参照)、インスタンス化されたUnitOfWorkUnitOfWorkとは異なります。各リポジトリ。

Unityと依存性注入を使用して、IUnitOfWorkをサービスレイヤーに注入し、このインスタンス化されたsharedUnitOfWorkクラスをそれぞれのリポジトリに渡すにはどうすればよいですか?

これが私の提案した(製造された)ソリューションです:

リポジトリ

public interface IRepository<TEntity> where TEntity : class
{
    TEntity Create();
    // omitted for brevity
}

public class Repository<TEntity> : IRepository<TEntity>
    where TEntity : class
{       
    private readonly DbContext _context;

    public Repository(IUnitOfWork uow)
    {
        _context = uow.Context;
    }

    public virtual TEntity Create(TEntity entity)
    {
        return _context.Set<TEntity>().Add(entity);         
    }   

    // omitted for brevity      
}

public interface IEmployeeRepository : IRepository<Employee>
{
}

public interface ICustomerRepository : IRepository<Customer>
{
}

public class EmployeeRepository : Repository<Employee>
{
    public EmployeeRepository(IUnitOfWork uow)
        : base(uow)
    {
    }
}

public class CustomerRepository : Repository<Customer>
{
    public CustomerRepository(IUnitOfWork uow)
        : base(uow)
    {
    }
}

DbContext Factory

public interface IDbContextFactory
{
    DbContext GetContext();
}

public class DbContextFactory : IDbContextFactory
{
    private readonly DbContext _context;

    public DbContextFactory()
    {
        _context = new MyDbContext("ConnectionStringName");
    }

    public DbContext GetContext()
    {
        return _context;
    }
}

作業単位

public interface IUnitOfWork
{
    void SaveChanges();
    DbContext Context { get; }
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
    private readonly DbContext _context;
    private bool disposed = false;

    public UnitOfWork(IDbContextFactory contextFactory)
    {
        _context = contextFactory.GetContext();
    }

    public void SaveChanges()
    {
        if (_context != null)
        {
            _context.SaveChanges();
        }
    }

    public DbContext Context
    {
        get { return _context; }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

サービス

public class CompanyService
{
    private readonly IUnitOfWork _uow;
    private readonly IEmployeeRepository _employeeRepository;
    private readonly ICustomerRepository _customerRepository;

    public CompanyService(IUnitOfWork uow, IEmployeeRepository employeeRepository, ICustomerRepository customerRepository)
    {           
        _uow = uow;
        _employeeRepository = employeeRepository;
        _customerRepository = customerRepository;
    }

    // over-simplified example method
    public void AddEmployeeAndCustomer()
    {
        _employeeRepository.Create(new Employee {Id = 1, Name = "Test Employee"});
        _customerRepository.Create(new Customer { Id = 2, Name = "Test Customer" });

        _uow.SaveChanges();
    }

}
15
Mark Erasmus

あなたが探しているのは、リクエストごとのライフタイムマネージャーであり、リクエストの期間中、UnitOfWorkインスタンスとDbContextインスタンスを1つだけ取得できると思います。 Unity 3には ASP.NET MVC用のUnityブートストラップ があり、これを実行できる PerRequestLifetimeManager があります。

ASP.NETを使用していない場合は、おそらくPerResolveLifetimeManagerを使用できます。私が見たもう1つのアプローチは、子コンテナーと組み合わせたHierarchicalLifetimeManagerです(これにより、子コンテナー内で登録がシングルトンになります)。

8
Randy Levy