24

MVCアプリケーション用のDbContext/POCOモデルを生成するために、Entity Frameworkデータベースファーストアプローチを使用します。私はコントローラのDbContextに依存しないようにして、必要に応じて別の永続化プロバイダに切り替えることができるようにしたいと考えています(たとえば単体テストの目的で)。Castle WindsorでEntity Frameworkを使用する

これを行うには、Castle Windsor IoCコンテナを使用します。私はDbContextをIUnitOfWorkサービスとして登録し、汎用IRepositoryサービスを登録する予定です。このサービスの実装は、モデルの集約ルートにアクセスして作業するために使用します。

私はウィンザーに新たなんだとEFでそれを使用する方法について多くの情報を見つけることができていない、と私は質問のカップルを持っている:私は分離したい場合

  • は、合理的なアプローチこれですアプリケーションからのEF?
  • IUnitOfWorkと一般的なIRepositoryサービスをインストール/登録するにはどうすればよいですか?
+3

これをマークダウン誰に...あなたはなぜ言ってコメントを提供したいと思いますか?あなたがどこかでポイントを逃したと思うなら、理由を説明することで私を助けるかもしれません。 –

+0

これは議論の質問であり、StackOverflow、特に最初のポイントには本当に適切ではないので、投票が中止されたと思います。 2つ目のポイントはCastle Windsorのサイトにあり、優れた文書があります。あなたの質問の内容を書いてください:単体テスト用のDbContextを嘲笑することは事実上不可能です(http://stackoverflow.com/a/13352779/861716)。私は、他のBLの純粋な単体テストプロジェクトの他に、DALテストのためにデータベースに対して「単体テスト」プロジェクトを使用します。カーストウィンザーは、インターフェースファクトリーからのインターフェース、インターフェースされていないインターフェース、インターフェース、バリデーターなどを注入します。 –

+0

@GertArnoldに感謝します。模擬問題に関して、私はDALの単体テストを望んでいませんが、アプリケーションレイヤ(コントローラなど)にモックリポジトリを提供してテストすることができるようにするためです。城のドキュメントは一般的には良いですが、NHibernateの統合について扱っており、その領域ではかなりスケッチです。 –

答えて

25

したがって、いくつかの結論。私はこれを、誰かが/ユニットテストEF、ウィンザーとMVCを一緒に使ってみようとしている人のために書いていると思った。

まず、DbContextはRepositoryとUnit of Workの両方のパターンを実装しているため、これらの実装が役立つかどうか、独自に作成する必要があるかどうかを確認する必要があります。

DDDパターンに従って、自分のリポジトリを作成することを選択しました。集約ルートごとに1つです。その理由:クエリコードをカプセル化し、アプリケーション層に漏れないようにし、アプリケーションコントローラをテストするときに簡単に疑似できるようにすること。 IRepository<TEntity>に基づいて汎用リポジトリを作成しました。そこにはたくさんの例があります。私はこれを良いものにしました:http://architects.dzone.com/articles/implementing-repository

一方、私はIUnitOfWorkサービスを削除し、代わりにデフォルトの実装を選択しました。しかし、私はIDbContext抽象化を作成しました(なぜマイクロソフトはこれを自分でやっていないのか分かりません)ので、リポジトリサービスをテストするときにDbContextを疑似できるようにしました。

私はIDbContextにリポジトリで使用したいDbContextのメンバーのみを与えました。だから、:

public interface IDbContext: IDisposable 
{ 
    Database Database { get; } 
    DbEntityEntry Entry(object entity); 
    IDbSet<TEntity> Set<TEntity>() where TEntity : class; 
    int SaveChanges(); 
} 

私はその後、私のIDbContextとIRepositoryサービスのためのウィンザーの施設とインストーラを作成しました:

public class EntityFrameworkFacility: AbstractFacility 
{ 
    protected override void Init() 
    { 
     Kernel.Register(Component.For<IDbContext>() 
           .ImplementedBy<MyEntities>() 
           .LifestylePerWebRequest(), 
         Component.For(typeof(IRepository<>)) 
           .ImplementedBy(typeof(Repository<>)) 
           .LifestylePerWebRequest()); 
    } 
} 

public class PersistenceInstaller : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.AddFacility<EntityFrameworkFacility>(); 
    } 
} 

最後のピースはIDbContextを実装するためにEntity Frameworkのコンテキストクラスを拡張して、影になりましたセット(IDbSetではなくDbSet返すように)方法:位(ウィンザーのドキュメントに示されているControllerFactory登録)ですべてこれにより

public partial class MyEntities : IDbContext 
{ 
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class 
    { 
     return base.Set<TEntity>(); 
    } 
} 

を、それが必要に応じて、コントローラのコンストラクタにIRepositoryオブジェクト(またはIDbContext)を注入するウィンザーを得ることが自明になる:

リポジトリ単体テストで
public ControllerBase(IRepository<Contact> repo) 
{ 
    _repo = repo; 
} 

、実際のリポジトリインスタンスはモックIDbContextで裏打ちすることができる。

mocks = new MockRepository(); 
context = mocks.StrictMock<IDbContext>(); 
repo = new Repository<Contact>(context); 
コントローラユニットテストでは、モックリポジトリを使用することができます

mocks = new MockRepository(); 
repo = mocks.StrictMock<IRepository<Contact>>(); 
ContactController controller = new ContactController(repo); 
+2

サンプルコードを提供してくれてありがとう:-) –

+1

MyEntitiesはDbContextを拡張する必要があります。 – SoWeLie

+0

実際、Entity Frameworkによって生成されたコンテキストクラスは、DbContextから継承します。これは、IDbContextもサポートするようにそのクラスを拡張する部分クラスです。 –

関連する問題