实体框架4中的存储库模式我们什么时候应该处置?

发布于 2024-10-05 00:03:32 字数 595 浏览 1 评论 0原文

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

我们应该尽快处理上下文吗?内存可能会泄漏或变得很大?

谁能澄清一下吗?多谢。

New to EF and I have noticed that using a repository pattern can really simplify things and will allow me to do some mocking too.So far so good.

My Question

A typical usage of the objectContext is to destroy as soon as possible see below

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

Using the Repository pattern I have noticed that nobody actually uses the "Using Pattern" eg

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

Should the idea be that we should dispose of the context as soon as possible otherwise the memory might leak or get very big?

Can anyone clarify? Thanks a lot.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

想你的星星会说话 2024-10-12 00:03:32

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

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

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

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

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

UnitOfWork 和存储库模式的一些起始实现:

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

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 包装的一次性实现 实体框架

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

Yes you should dispose context even if you are using repository. It is not clear what advantage does your Repository implementation give you because you are still providing ObjectContext as constructor's parameter, aren't you?

IMO the main reason for using Repository and custom UnitOfWork is persistance ignorance = hidding EF code from upper application layers because ObjectContext + ObjectSet themselves are implementation of repository and unit of work patterns.

If I'm using repository, I'm always wrapping whole EF code, so the public interface of my repository doesn't provide any information about EF related infrastructure. In that case it is up to me how I deal with ObjectContext.

For easy straight forward CRUD scenarios, I can wrap context creation and disposing into each repository method. In more complex scenarios I'm using additional class - UnitOfWork (UoW), which wraps context creation and disposing and it triggers saving changes into database. It also acts as factory for all repositories and passes instance of created context into repositories' constructors.

Most of the time I'm programming services or web applications so I'm dealing with detached objects. I'm always using single UoW instance for request processing. So the UoW is created at the beginning of request processing and released at the end of request processing. In case of WinForms / WPF applications and attached objects I think the good idea is to have UoW / ObjectContext instance "per form" - there is article describing this approach with NHibernate session (same as EF ObjectContext) in MSDN magazine.

Some starting implementation of UnitOfWork and Repository patterns:

Context holder and abstract factory for repositories

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

  SaveChanges();
}

Repository for detached entities

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

Disposable implementation of UnitOfWork wrapping 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;
       }
     }
   }
}

Base repository implementation

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

Usage when selecting data

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

Usage when modifing data

using (var uow = new UnitOfWork(connectionString))
{
  uow.MyEntitiesRepository.Update(entity);
  uow.SaveChanges();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文