FactoryとUnitOfWorkにジェネリック型パラメーターを与えることは、解決策かもしれません:
public class UnitOfWork<T> : IUnitOfWork<T>
where T : DbContext, new()
{
private T _context;
private readonly IDatabaseFactory<T> _databaseFactory;
protected T Context
{
get { return _context ?? (_context = _databaseFactory.Get()); }
}
public UnitOfWork(IDatabaseFactory<T> factory)
{
_databaseFactory = factory;
_context = _databaseFactory.Get();
}
//More code
}
public class DatabaseFactory<T> : Disposable, IDatabaseFactory<T>
where T : DbContext, new()
{
private T _dataContext;
public T Get()
{
return _dataContext ?? (_dataContext = new T());
}
protected override void DisposeCore()
{
if (_dataContext != null)
_dataContext.Dispose();
}
}
その場合IDatabaseFactory
、およびIUnitWork
インターフェイスも汎用である必要があります。
次に、さまざまなコンテキストの作業単位を作成できます。
var factory1 = new DatabaseFactory<SiteModelContainer>();
var unitOfWork1 = new UnitOfWork<SiteModelContainer>(factory1);
var factory2 = new DatabaseFactory<AnotherModelContainer>();
var unitOfWork2 = new UnitOfWork<AnotherModelContainer>(factory2);
編集:
サービスクラスのEFへの依存を取り除くには、次のような方法を試すことができます。サービスは、次の3つのインターフェースのみを認識します。
public interface IUnitOfWorkFactory
{
IUnitOfWork Create(string contextType);
}
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> CreateGenericRepository<TEntity>()
where TEntity : class;
void Commit();
}
public interface IRepository<T>
{
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
void Attach(T entity);
void Add(T entity);
// etc.
}
EF固有の特別な実装は次のとおりです。
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
public IUnitOfWork Create(string contextType)
{
switch (contextType)
{
case "SiteModelContainer":
return new UnitOfWork<SiteModelContainer>();
case "AnotherModelContainer":
return new UnitOfWork<AnotherModelContainer>();
}
throw new ArgumentException("Unknown contextType...");
}
}
public class UnitOfWork<TContext> : IUnitOfWork
where TContext : DbContext, new()
{
private TContext _dbContext;
public UnitOfWork()
{
_dbContext = new TContext();
}
public IRepository<TEntity> CreateGenericRepository<TEntity>()
where TEntity : class
{
return new Repository<TEntity>(_dbContext);
}
public void Commit()
{
_dbContext.SaveChanges();
}
public void Dispose()
{
_dbContext.Dispose();
}
}
public class Repository<T> : IRepository<T>
where T : class
{
private DbContext _dbContext;
private DbSet<T> _dbSet;
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<T>();
}
public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dbSet.Where(predicate);
}
public void Attach(T entity)
{
_dbSet.Attach(entity);
}
public void Add(T entity)
{
_dbSet.Add(entity);
}
// etc.
}
あなたのサービスはIUnitOfWorkFactory
注入されます:
public class MyService
{
private IUnitOfWorkFactory _factory;
public MyService(IUnitOfWorkFactory factory)
{
_factory = factory;
}
public MyMethod()
{
using(var unitOfWork1 = _factory.Create("SiteModelContainer"))
{
var repo1 = unitOfWork1.
CreateGenericRepository<SomeEntityTypeInSiteModel>();
// Do some work
unitOfWork1.Commit();
}
using(var unitOfWork2 = _factory.Create("AnotherModelContainer"))
{
var repo2 = unitOfWork2.
CreateGenericRepository<SomeEntityTypeInAnotherModel>();
// Do some work
unitOfWork2.Commit();
}
}
}
サービスが作成されると、ファクトリの具体的なインスタンスが注入されます。
var service = new MyService(new UnitOfWorkFactory());
大変な作業は抽象リポジトリとその実装にあることを覚えておいてください。サービスクラスにEFコンテキストがなくなるとすぐに、データを操作するために必要なすべてのシナリオをサポートするリポジトリインターフェイスの多くのメソッドを模倣する必要があります。