Entity Framework с использованием шаблона репозитория, единицы работы и единства
Используя комбинацию из этот пример и эта реализация Я пытаюсь для создания решения, которое отделяет класс UnitOfWork
от отдельных репозиториев, поскольку они нарушают принцип открытого закрывания, поскольку каждый раз, когда вы добавляете новый репозиторий, вам придется изменить класс UnitOfWork
. Я использую Unity в качестве контейнера IoC для подключения зависимостей.
Проблема заключается в том, что при автоматической компоновке UnitOfWork
, IDbContext
и репозиториев (IEmployeeRepository
и ICustomerRepository
) с помощью Unity репозитории будут добавлены отдельные экземпляры UnitOfWork
, что, конечно, побеждает цель. Мне нужно поделиться контекстом через репозитории, и кажется, что мне не хватает части этой головоломки - на данный момент (см. Уровень сервиса) созданный UnitOfWork
будет отличаться от UnitOfWork
для каждого из репозиториев.
Как вставить IUnitOfWork
в уровень обслуживания и передать этот экземпляр общего класса UnitOfWork
в соответствующие репозитории, используя Unity и инъекцию зависимостей?
Здесь мое предлагаемое (сфабрикованное) решение:
Хранилища
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();
}
}
Ответы
Ответ 1
Я думаю, что то, что вы ищете, - это менеджер жизненного цикла для каждого запроса, так что вы получаете только один экземпляр UnitOfWork и один экземпляр DbContext на время запроса. Unity 3 имеет Unity bootstrapper для ASP.NET MVC, который имеет PerRequestLifetimeManager, который позволяет вам сделать это.
Если вы не используете ASP.NET, вы, вероятно, можете использовать PerResolveLifetimeManager. Другим подходом, который я видел, является HierarchicalLifetimeManager в сочетании с дочерним контейнером (который делает регистрацию одноэлементным в дочернем контейнере).