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

use*_*969 31 repository-pattern entity-framework-4

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

我的问题

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

using (var context = new SchoolEntities())
{    
    context.AddToDepartments(department);    
    context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

使用Repository模式我注意到没有人真正使用"使用模式",例如

using (var repository= new Repository<Student>(new MyContext))
{    
    repository.Add(myStudentEntity)  
    repository.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

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

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

Lad*_*nka 50

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

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

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

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

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

一些单元开始实现UnitOfWork和Repository模式:

上下文持有者和存储库的抽象工厂

public interface IUnitOfWork
{
  IRepository<MyEntity> MyEntityRepository { get; }
  // Repositories for other entities

  SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

分离实体的存储库

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);
}
Run Code Online (Sandbox Code Playgroud)

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;
       }
     }
   }
}
Run Code Online (Sandbox Code Playgroud)

基础存储库实现

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

选择数据时的用法

using (var uow = new UnitOfWork(connectionString))
{
  var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1);
  // Do something with entity
}
Run Code Online (Sandbox Code Playgroud)

修改数据时的用法

using (var uow = new UnitOfWork(connectionString))
{
  uow.MyEntitiesRepository.Update(entity);
  uow.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

  • 非常深入的回答 - 但是,您的`UnitOfWork`类具有单个本地范围的`IRepository`实例,这意味着工作单元正在定义要使用的存储库.这是不正确的.工作单元的要点是处理跨多个存储库的事务(UoW通常通过其ctor接受1-*存储库).这个实现根本没有真正处理它.也许这对OP来说很好. (2认同)