web-dev-qa-db-ja.com

Entity Framework 4のリポジトリパターンはいつ破棄する必要がありますか?

EFは初めてで、リポジトリパターンを使用すると、物事が本当に単純化され、モックも実行できるようになることに気づきました。これまでのところ、これで十分です。

私の質問

ObjectContextの一般的な使用法は、できるだけ早く破棄することです。以下を参照してください。

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

リポジトリパターンの使用実際に「パターンの使用」を使用している人はいないことに気づきました。

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

コンテキストをできるだけ早く破棄する必要があるという考えでしょうか。そうしないと、メモリがリークしたり、非常に大きくなったりする可能性があります。

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

31
user9969

はい、リポジトリを使用している場合でも、コンテキストを破棄する必要があります。コンストラクターのパラメーターとしてObjectContextを提供しているため、リポジトリーの実装がどのような利点をもたらすのかは明確ではありませんか?

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

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

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

ほとんどの場合、私はサービスまたはWebアプリケーションをプログラミングしているので、分離オブジェクトを扱っています。私は常にリクエスト処理に単一のUoWインスタンスを使用しています。したがって、UoWは要求処理の開始時に作成され、要求処理の終了時に解放されます。 WinForms/WPFアプリケーションとアタッチされたオブジェクトの場合、UoW/ObjectContextインスタンスを「フォームごとに」持つことをお勧めします 記事 このアプローチを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);
}

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

データ選択時の使用法

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();
}
48
Ladislav Mrnka