2010-11-28 11 views
31

EFの新機能で、リポジトリパターンを使用すると、実際には物事を単純化でき、私にもいくつかの嘲笑をさせることができることに気付きました。エンティティ・フレームワーク4のリポジトリ・パターン私たちはいつ処分すべきですか?

私の質問

のObjectContextの典型的な使用法は、私は誰もが実際に「使用パターン」などを使用していないことに気づいたリポジトリパターンを使用して

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

下記参照できるだけ早く破壊することである

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

できるだけ早くコンテキストを破棄しなければ、メモリがリークしたり非常に大きくなったりする可能性がありますか?

誰でも明示できますか?どうもありがとう。

答えて

47

はい、リポジトリを使用している場合でもコンテキストを破棄する必要があります。 ObjectContextをコンストラクタのパラメータとして提供しているので、リポジトリの実装があなたに与える利点ははっきりしません。

IMOリポジトリとカスタムUnitOfWorkを使用する主な理由は、ObjectContext + ObjectSet自体がリポジトリと作業単位パターンの実装であるため、上位アプリケーション層からの永続性ignorance = hidding EFコードです。

リポジトリを使用している場合、私は常にEFコード全体をラッピングしているので、リポジトリのパブリックインターフェイスはEF関連インフラストラクチャに関する情報を提供しません。その場合、ObjectContextをどのように処理するかは私の責任です。

簡単な単純CRUDシナリオのために、コンテキストの作成と各リポジトリメソッドへの処分をラップすることができます。より複雑なシナリオでは、私は追加のクラス(UnitOfWork(UoW))を使用しています。これは、コンテキストの作成と廃棄をラップし、変更をデータベースに保存します。また、すべてのリポジトリのファクトリとして機能し、作成されたコンテキストのインスタンスをリポジトリのコンストラクタに渡します。

ほとんどの場合、私はサービスやWebアプリケーションをプログラミングしているので、デタッチされたオブジェクトを扱っています。私は常にリクエスト処理のために単一のUoWインスタンスを使用しています。したがって、UoWは要求処理の開始時に作成され、要求処理の終了時に解放されます。 WinForms/WPFアプリケーションと添付オブジェクトの場合は、UoW/ObjectContextインスタンスを "フォームごとに"持たせることをお勧めします。 - articleがNHibernateセッション(EF ObjectContextと同じ)でこのアプローチをMSDNマガジンに記述しています。

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

Enitityフレームワークをラップた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); 
    } 
} 

使用データ

+1

using (var uow = new UnitOfWork(connectionString)) { uow.MyEntitiesRepository.Update(entity); uow.SaveChanges(); } 
Fantastic.Thanksを・修正するときに、データ

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

使用法を選択する場合!私がこれらのリポジトリに持つ唯一の問題は、 "Include" Eagerの読み込みを処理していないということです。あなたのリポジトリをどうやって熱心に読み込んでいますか? – user9969

+1

これは難しい部分です。なぜなら、IncludeはEF ObjectQueryの機能だからです。私は通常、GeneralRepositoryから継承されたリポジトリを作成し、必要なインクルードをオーバーライドされたGetQueryに追加します。しかし、いくつかのクエリに対してのみ熱心な読み込みを有効にする必要がある場合、それはあなたを助けません。その場合は別のものが必要です。私はLinq-To-SQLからLoadOptionsのようなものを実装し、このオプションをUnitOfWorkまたはRepositoryに渡すことを想像することができます。次に、optinsを使用してすべての設定を設定します。 –

+2

非常に深い答えですが、あなたの 'UnitOfWork'クラスは単一のローカルスコープの' IRepository'インスタンスを持っています。これは作業ユニットが作業するリポジトリを定義していることを意味します。これは正しくありません。作業単位のポイントは、複数のリポジトリ間でトランザクションを処理することです(UoWは通常、そのエージェントを介して1- *リポジトリを受け入れます)。この実装は実際にはそれをまったく処理しません。多分これはOPのために罰金です。 – RPM1984

関連する問題