2016-09-25 48 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(); 
    } 
}