Да, вы должны располагать контекстом, даже если вы используете репозиторий. Не ясно, какое преимущество дает реализация Repository, потому что вы все еще предоставляете ObjectContext в качестве параметра конструктора, не так ли?
ИМО основной причиной использования репозитория и пользовательского UnitOfWork является постоянное невежество = скрытие кода EF от верхних уровней приложения, поскольку сами ObjectContext + ObjectSet являются реализацией шаблонов репозитория и единицы работы.
Если я использую репозиторий, я всегда оборачиваю весь код EF, поэтому открытый интерфейс моего репозитория не предоставляет никакой информации об инфраструктуре, связанной с EF. В таком случае мне решать, как я обращаюсь с ObjectContext.
Для простых и понятных сценариев CRUD я могу обернуть создание и размещение контекста в каждый метод репозитория. В более сложных сценариях я использую дополнительный класс - UnitOfWork (UoW), который оборачивает создание и удаление контекста и инициирует сохранение изменений в базе данных. Он также действует как фабрика для всех репозиториев и передает экземпляр созданного контекста в конструкторы репозиториев.
Большую часть времени я занимаюсь программированием сервисов или веб-приложений, поэтому имею дело с отдельными объектами. Я всегда использую один экземпляр UoW для обработки запросов. Таким образом, UoW создается в начале обработки запроса и освобождается в конце обработки запроса. В случае приложений WinForms / WPF и прикрепленных объектов я думаю, что хорошей идеей является наличие экземпляра UoW / ObjectContext «на форму» - есть статья , описывающая этот подход с помощью сеанса NHibernate (аналогично EF ObjectContext) в MSDN журнал.
Некоторая начальная реализация шаблонов UnitOfWork и Repository:
Держатель контекста и абстрактная фабрика для репозиториев
public interface IUnitOfWork
{
IRepository<MyEntity> MyEntityRepository { get; }
// Repositories for other entities
SaveChanges();
}
Хранилище для отдельных объектов
public interface IRepository<T> where T : class
{
IQueryable<T> GetQuery();
void Insert(T entity);
void Delete(T entity);
// In very complex scenarios with big object graphs you will probably give up
// using detached approach and you will always load your entities from DB before
// deleting or updating them. In such case you will not need Update method at all.
void Update(T entity);
}
Одноразовая реализация оболочки Enitity UnitOfWork
public class UnitOfWork : IUnitOfWork, IDisposable
{
private ObjectContext _context = null;
public UnitOfWork(string connectionString)
{
if (String.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString");
_context = new ObjectContext(connectionString);
}
private IRepository<MyEntity> _myEntityRepository;
public IRepository<MyEntity> MyEntityRepository
{
get
{
return _myEntityRepository ?? (_myEntityRepository = new GeneralRepository<MyEntity>(_context));
}
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
Реализация базового репозитория
public class GeneralRepository<T> : IRepository<T> where T : class
{
private ObjectSet<T> _set;
private ObjectContext _context;
public GeneralRepository(ObjectContext context)
{
if (context == null) throw new ArgumentNullException("context");
_context = context;
_set = context.CreateObjectSet<T>();
}
// Override this method for example if you need Includes
public virtual IQueryable<T> GetQuery()
{
return _set;
}
// Override following methods if you are working with object graphs.
// Methods do not execute operations in database. It is responsibility of
// UnitOfWork to trigger the execution
public virtual void Insert(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.AddObject(entity);
}
// These impelementations are for detached scenarios like web application
public virtual void Delete(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.Attach(entity);
_set.DeleteObject(entity);
}
public virtual void Update(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
_set.Attach(entity);
_context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
}
Использование при выборе данных
using (var uow = new UnitOfWork(connectionString))
{
var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1);
// Do something with entity
}
Использование при изменении данных
using (var uow = new UnitOfWork(connectionString))
{
uow.MyEntitiesRepository.Update(entity);
uow.SaveChanges();
}