2009-07-23 2 views
7

私はMVPとEntity Frameworkの世界でかなり新しいです。EF ObjectContext、サービスとリポジトリ - コンテキストライフタイムを管理する。

私は現在View + Presenterコンビネーションを持っています。ビューにはEditとDeleteの2つのイベントがあり、発表者はこれらのイベントをリッスンします。私はサービスオブジェクトとリポジトリも設定しています。サービス層は、建設のためには(1つ下にトップオブジェクトを渡しているので、ObjectContextを取るいくつかのリポジトリの実装取ります

ObjectContext 
    | 
    V 
Repositries 
    | 
    V 
Service Object 
    | 
    V 
Presenter 

を今問題となっていること、私は一番上にオブジェクトコンテキストを作成するときに、それは、プレゼンターが生きている間、編集と削除がサービスから同じコンテキストインスタンスを使用することを意味しています。ServiceObject.DeleteとServiceObject.Editを呼び出すと、変更トラッキングを管理するのが難しくなる同じコンテキストが使用されます。私が理解しているところでは、文脈は実際には短命で、作業単位のためだけに、私には編集と削除の両方が異なっています。

エンティティフレームワークでDIを行い、コンテキストの存続時間をどのように管理しますか?

私はリポジトリの横にオブジェクトのコンテキストを新しくした人を見てきましたが、これは良いパターンです。私はそのようにそれを行う場合

ServiceObject{ 
    public void Edit(// some args) { 
    Using(var context = new MyObjectContext) { 
     var repo = new MyRepo(context); 
     var entity = repo.GetForID(12); 
     // Do some stuff for edit 
     context.SaveChanges(); 
    } 
    } 
} 

しかし、私はもはやServiceObjectのコンストラクタに私のリポジトリを渡すと:(DIは致しておりません。

はそれとも私がサービスオブジェクトでは、何かのようにそれを行うべきではありません。

私はこのような状況で何ができますか?

誰もが、私はそれを見ることができます任意のオープンソースプロジェクトは、この問題で私を助けて知っています。

ありがとうございます。

答えて

24

私はトップ(発表者)から参加者の関係を説明します。

Presenterは依存関係を通じてサービスオブジェクトを取得します。サービス機能は、その契約を使用して概説されます。

class Presenter 
{ 
    public Presenter(IService service) 
    { 
    ... 
    } 
} 

サービス実装は、特定のデータアクセスレイヤの実装から抽象化されています。基本的に、サービスがデータソースとのやり取りを必要とする何らかのアクションを実行するときには、それは作業ユニットのインスタンスを作成し、完了したときにそれを廃棄します。

interface IService 
{ 
    void Do(); 
} 

class Service : IService 
{ 
    private readonly IUnitOfWorkFactory unitOfWorkFactory; 
    public Service(IUnitOfWorkFactory unitOfWorkFactory) 
    { 
    this.unitOfWorkFactory = unitOfWorkFactory; 
    } 

    public void Do() 
    { 
    // Whenever we need to perform some data manipulation we create and later dispose 
    // dispose unit of work abstraction. It is created through a factory to avoid 
    // dependency on particular implementation. 
    using(IUnitOfWork unitOfWork = this.unitOfWorkFactory.Create()) 
    { 
     // Unit of work holds Entity Framework ObjectContext and thus it used 
     // create repositories and propagate them this ObjectContext to work with 
     IRepository repository = unitOfWork.Create<IRepository>(); 
     repository.DoSomethingInDataSource(); 

     // When we are done changes must be commited which basically means committing 
     // changes of the underlying object context. 
     unitOfWork.Commit(); 
    } 
    } 
} 


/// <summary> 
/// Represents factory of <see cref="IUnitOfWork"/> implementations. 
/// </summary> 
public interface IUnitOfWorkFactory 
{ 
    /// <summary> 
    /// Creates <see cref="IUnitOfWork"/> implementation instance. 
    /// </summary> 
    /// <returns>Created <see cref="IUnitOfWork"/> instance.</returns> 
    IUnitOfWork Create(); 
} 

/// <summary> 
/// Maintains a list of objects affected by a business transaction and coordinates the writing out of 
/// changes and the resolution of concurrency problems. 
/// </summary> 
public interface IUnitOfWork : IDisposable 
{ 
    /// <summary> 
    /// Creates and initializes repository of the specified type. 
    /// </summary> 
    /// <typeparam name="TRepository">Type of repository to create.</typeparam> 
    /// <returns>Created instance of the repository.</returns> 
    /// <remarks> 
    /// Created repositories must not be cached for future use because once this 
    /// <see cref="IUnitOfWork"/> is disposed they won't be able to work properly. 
    /// </remarks> 
    TRepository Create<TRepository>(); 

    /// <summary> 
    /// Commits changes made to this <see cref="IUnitOfWork"/>. 
    /// </summary> 
    void Commit(); 
} 

/// <summary> 
/// Represents factory of <see cref="UnitOfWork"/>s. 
/// </summary> 
public class UnitOfWorkFactory : IUnitOfWorkFactory 
{ 
    private readonly IUnityContainer container; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="UnitOfWorkFactory"/> class. 
    /// </summary> 
    /// <param name="container"> 
    /// Dependency injection container instance used to manage creation of repositories 
    /// and entity translators. 
    /// </param> 
    public UnitOfWorkFactory(IUnityContainer container) 
    { 
       this.conainer = container; 
    } 


    /// <summary> 
    /// Creates <see cref="IUnitOfWork"/> implementation instance. 
    /// </summary> 
    /// <returns>Created <see cref="IUnitOfWork"/> instance.</returns> 
    public IUnitOfWork Create() 
    { 
     var unitOfWork = this.container.Resolve<UnitOfWork>(); 
     unitOfWork.SetupObjectContext(); 
     return unitOfWork; 
    } 

    ... other members elidged for clarity 
} 

IUnitOfWorkの実装はIUnityContainerのインスタンスを受信し、子コンテナを作成し、そこのObjectContextインスタンスを登録します。この子コンテナは、リポジトリの作成およびObjectContextの伝播に使用されます。ここで

はIUnitOfWorkの単純化された実装です:良いことだ

class UnitOfWork : IUnitOfWork 
{ 
    private readonly IUnityContainer container; 
    private ObjectContext objectContext; 

    public UnitOfWork (IUnityContainer container) 
    { 
    this.container = container.CreateChildContainer(); 
    } 

    public void SetupObjectContext() 
    { 
    this.objectContext = ... // Create object context here 
    this.container.RegisterInstance(context.GetType(), context); 
    } 

    public void Create<TRepository>() 
    { 
    // As long as we registered created object context instance in child container 
    // it will be available now to repositories during resolve 
    return this.container.Resolve<TRepository>(); 
    } 

    public void Commit() 
    { 
    this.objectContext.SaveChanges(); 
    } 
} 

class Repository : IRepository 
{ 
    private readonly SomeObjectContext objectContext; 

    public Repository(SomeObjectContext objectContext) 
    { 
    this.objectContext = objectContext; 
    } 

    public void DoSomethingInDataSource() 
    { 
    // You can use object context instance here to do the work 
    } 
} 
+1

uuh! – Roubachof

関連する問題