2016-09-25 27 views
0

私はasp.net mvc、Entityframework 6とDIシナリオのUnityを使用しています。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

あなたは 'GenericUoW'に' IDisposable'を実装するべきではありません。コンシューマークラスは依存関係(コンポジションルートとコンテナのみ)の所有権を持たず、依存関係(この場合は '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(); 
    } 
} 
関連する問題