この例 と この実装 から提供される組み合わせを使用して、個々のリポジトリからUnitOfWork
クラスを分離するソリューションを作成しようとしています。オープンクローズ原則。新しいリポジトリを追加するたびに、UnitOfWork
クラスを変更する必要があるためです。 UnityをIoCコンテナーとして使用して、依存関係を結び付けています。
私が抱えている問題は、Unityを使用してUnitOfWork
、IDbContext
とリポジトリ(IEmployeeRepository
とICustomerRepository
)を自動的に接続すると、リポジトリが注入されることです。 UnitOfWork
の個別のインスタンスを使用しますが、これはもちろん目的を無効にします。リポジトリ間でコンテキストを共有する必要がありますが、このパズルのピースが欠けているようです。現時点では(サービスレイヤーを参照)、インスタンス化されたUnitOfWork
はUnitOfWork
とは異なります。各リポジトリ。
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();
}
}
あなたが探しているのは、リクエストごとのライフタイムマネージャーであり、リクエストの期間中、UnitOfWorkインスタンスとDbContextインスタンスを1つだけ取得できると思います。 Unity 3には ASP.NET MVC用のUnityブートストラップ があり、これを実行できる PerRequestLifetimeManager があります。
ASP.NETを使用していない場合は、おそらくPerResolveLifetimeManagerを使用できます。私が見たもう1つのアプローチは、子コンテナーと組み合わせたHierarchicalLifetimeManagerです(これにより、子コンテナー内で登録がシングルトンになります)。