实体框架中的存储库模式4何时应该处置?

时间:2010-11-28 08:26:00

标签: entity-framework-4 repository-pattern

EF新手,我注意到使用存储库模式可以真正简化事情并允许我做一些嘲弄。太好了。

我的问题

objectContext的典型用法是尽快销毁,见下文

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

使用Repository模式我注意到没有人真正使用“Using Pattern”,例如

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

我们应该尽快处理上下文,否则内存可能会泄漏或变得非常大?

任何人都可以澄清吗?非常感谢。

1 个答案:

答案 0 :(得分:47)

是的,即使您正在使用存储库,也应该处置上下文。目前尚不清楚您的Repository实现给您带来了什么好处,因为您仍然提供ObjectContext作为构造函数的参数,不是吗?

IMO使用Repository和自定义UnitOfWork的主要原因是持久无知=隐藏来自上层应用程序层的EF代码,因为ObjectContext + ObjectSet本身是存储库和工作单元格的实现。

如果我正在使用存储库,我总是包装整个EF代码,因此我的存储库的公共接口不提供有关EF相关基础结构的任何信息。在这种情况下,我应该如何处理ObjectContext。

对于简单直接的CRUD场景,我可以将上下文创建和处理包装到每个存储库方法中。在更复杂的场景中,我正在使用其他类 - UnitOfWork(UoW),它包装上下文创建和处理,并触发将更改保存到数据库中。它还充当所有存储库的工厂,并将创建的上下文的实例传递到存储库的构造函数。

大多数时候我正在编程服务或Web应用程序,所以我正在处理分离的对象。我总是使用单个UoW实例进行请求处理。因此,UoW在请求处理开始时创建,并在请求处理结束时释放。在WinForms / WPF应用程序和附加对象的情况下,我认为好主意是在每个表单中都有UoW / ObjectContext实例 - 在MSDN杂志中有article描述这种方法与NHibernate会话(与EF ObjectContext相同)。

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

UnitOfWork包装Enitity框架的一次性实现

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