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();
}
我们应该尽快处理上下文,否则内存可能会泄漏或变得非常大?
任何人都可以澄清吗?非常感谢。
答案 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();
}