Подтвердить что ты не робот

Шаблон хранилища в структуре Entity 4, когда мы должны распоряжаться?

Новое для EF, и я заметил, что использование шаблона репозитория может действительно упростить вещи и позволит мне делать некоторые издевательства слишком. Очень хорошо.

Мой вопрос

Типичное использование objectContext заключается в том, чтобы уничтожить как можно скорее см. ниже

using (var context = new SchoolEntities())
{    
    context.AddToDepartments(department);    
    context.SaveChanges();
}

Используя шаблон репозитория, я заметил, что на самом деле никто не использует "Использование шаблона", например

using (var repository= new Repository<Student>(new MyContext))
{    
    repository.Add(myStudentEntity)  
    repository.SaveChanges();
}

Если идея состоит в том, что мы должны как можно скорее избавиться от контекста, иначе память может протечь или стать очень большой?

Может ли кто-нибудь уточнить? Большое спасибо.

4b9b3361

Ответ 1

Да, вы должны использовать контекст, даже если вы используете репозиторий. Неясно, какое преимущество дает вам реализация Репозитория, потому что вы все еще предоставляете ObjectContext в качестве параметра конструктора, не так ли?

IMO основной причиной использования репозитория и пользовательского UnitOfWork является игнорирование persistance = код EF, который высвечивается из верхних слоев приложения, поскольку ObjectContext + ObjectSet - это реализация репозитория и единицы рабочих шаблонов.

Если я использую репозиторий, я всегда обертываю весь EF-код, поэтому открытый интерфейс моего репозитория не предоставляет никакой информации об инфраструктуре, связанной с EF. В этом случае это зависит от меня, как я общаюсь с ObjectContext.

Для упрощения прямых сценариев CRUD я могу обернуть создание и удаление контекста в каждом методе репозитория. В более сложных сценариях я использую дополнительный класс - UnitOfWork (UoW), который включает создание и удаление контекста и запускает сохранение изменений в базе данных. Он также действует как factory для всех репозиториев и передает экземпляр созданного контекста в конструкторы репозиториев.

В большинстве случаев я программирую службы или веб-приложения, поэтому имею дело с отдельными объектами. Я всегда использую один экземпляр UoW для обработки запросов. Таким образом, UoW создается в начале обработки запроса и освобождается в конце обработки запроса. В случае приложений WinForms/WPF и связанных объектов я думаю, что хорошая идея - иметь экземпляр UoW/ObjectContext "для каждой формы" - есть статья, описывающая этот подход с сеансом NHibernate (такой же, как EF ObjectContext) в журнале MSDN.

Некоторая начальная реализация шаблонов UnitOfWork и Repository:

Контекст и абстрактный factory для репозиториев

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);
}

Одноразовая реализация оболочки UnitOfWork Enitity framework

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();
}