2016-09-25 49 views
0

我使用的是asp.net mvc,Entityframework 6和Unity for DI场景。已经处理了DbContext对象:如何防止对象被丢弃?

我找不到为什么我的DbContext对象被放置得太早。

我将GenericWoU类注入到PeopleController类中。当我调用ListPerson动作时,一切正常,但是DbContext被处置。所以,如果我尝试编辑列表中的任何人,出现以下错误:

的操作无法完成,因为的DbContext一直 布置

我怎样才能防止被设置在的DbContext太早了?

这是我的工作类的通用单位:

public class GenericUoW : IDisposable, IGenericUoW 
    { 
     private readonly DbContext entities = null; 
     public Dictionary<Type, object> repositories = new Dictionary<Type, object>(); 

     public GenericUoW(DbContext entities) 
     { 
      this.entities = entities; 
     } 

    public IRepository<T> Repository<T>() where T : class 
    { 
     if (repositories.Keys.Contains(typeof(T)) == true) 
     { 
      return repositories[typeof(T)] as IRepository<T>; 
     } 

     IRepository<T> repo = new GenericRepository<T>(entities); 
     repositories.Add(typeof(T), repo); 
     return repo; 
    } 

    public void SaveChanges() 
    { 
     entities.SaveChanges(); 
    } 

    private bool disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.disposed) 
     { 
      if (disposing) 
      { 
       entities.Dispose(); 
      } 
     } 
     this.disposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
} 

这里是我GenericRepository类:

class GenericRepository<T> : IRepository<T> where T : class 
{ 
    private readonly DbContext entities = null; 
    private DbSet<T> _objectSet; 

    public GenericRepository(DbContext _entities) 
    { 
     entities = _entities; 
     _objectSet = entities.Set<T>(); 
    } 

    public IEnumerable<T> GetAll(Func<T, bool> predicate = null) 
    { 
     if (predicate != null) 
     { 
      return _objectSet.Where(predicate); 
     } 

     return _objectSet.AsEnumerable(); 
    } 

    public T Get(Func<T, bool> predicate) 
    { 
     return _objectSet.First(predicate); 
    } 

    public void Add(T entity) 
    { 
     _objectSet.Add(entity); 
    } 

    public void Attach(T entity) 
    { 
     _objectSet.Attach(entity); 
    } 

    public void Delete(T entity) 
    { 
     _objectSet.Remove(entity); 
    } 
} 

这里是我ContainerBootstrapper类:

public class ContainerBootstrapper 
{ 
    public static IUnityContainer Initialise() 
    { 
     var container = BuildUnityContainer(); 
     DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
     return container; 
    } 
    private static IUnityContainer BuildUnityContainer() 
    { 
     var container = new UnityContainer(); 

     DbContext entities = new TeijonStuffEntities(); 
     container.RegisterInstance(entities); 

     GenericUoW GUoW = new GenericUoW(entities); 
     container.RegisterInstance(GUoW); 

     MvcUnityContainer.Container = container; 
     return container; 
    } 
} 
+1

你不应该执行'IDisposable'上'GenericUoW'。不要注入处理注入的依赖关系,因为消费类没有依赖关系的所有权(只有组合根和容器),它不知道依赖关系(本例中的DbContext)应该是是否处置。除去“Dispose”功能可能会真正解决您的问题,但很难说清楚,因为缺少足够的详细信息来描述确切原因。 – Steven

+0

相关:https://stackoverflow.com/questions/12259534/is-it-a-leaky-abstraction-if-implementation-of-interface-calls-dispose – Steven

+0

相关:https://stackoverflow.com/a/30287923/264697 – Steven

回答

2

普遍的问题是您的组件通过处置它来对其依赖关系拥有所有权。一个组件永远不知道它的依赖关系的生命周期是什么以及它们以后是否可能被其他组件使用(甚至可能在相同的请求中)。所以这使得处理依赖关系变得危险(甚至是错误的)。

相反,作为一般的经验法则,创建组件的人是负责处理它的人。因为在你的情况下Unity创建这个对象,所以它应该处理它(它会)。

这意味着您应该从GenericUoW中删除所有的处理功能。这不仅是唯一正确的方法,它实际上要维护的代码少得多,因为这不仅影响GenericUoW,而且还影响GenericUoW的所有可能的直接和间接消费者。在你的设计中,他们都必须执行IDisposable。正确应用DI时,可以省略此操作,这会对代码的可维护性产生巨大影响。

长话短说,在GenericUoW更改为以下:

public sealed class GenericUoW : IGenericUoW 
{ 
    private readonly Dictionary<Type, object> repositories =new Dictionary<Type, object>(); 
    private readonly DbContext entities; 

    public GenericUoW(DbContext entities) 
    { 
     this.entities = entities; 
    } 

    public IRepository<T> Repository<T>() where T : class 
    { 
     if (!repositories.Keys.Contains(typeof(T))) { 
      IRepository<T> repo = new GenericRepository<T>(entities); 
      repositories.Add(typeof(T), repo); 
     } 

     return (IRepository<T>)repositories[typeof(T)]; 
    } 

    public void SaveChanges() { 
     entities.SaveChanges(); 
    } 
}