(注:私の質問は、3か月前に この質問 を尋ねた人と非常によく似た懸念を持っていますが、答えられませんでした。)
私は最近MVC3 + Entity Frameworkの使用を開始しましたが、ベストプラクティスは、リポジトリパターンを使用してDALへのアクセスを一元化することであると読み続けています。これには、DALをドメイン、特にビューレイヤーから分離しておく必要があるという説明も含まれています。しかし、私が見た例では、リポジトリは単にDALエンティティを返します(またははのように見えます)。つまり、私の場合、リポジトリはEFエンティティを返します。 。
だから私の質問は、それがDALエンティティのみを返す場合、リポジトリは何が良いのかということです。これにより、レイヤー間でDALエンティティを渡す問題が解消されない複雑なレイヤーが追加されませんか?リポジトリパターンが「DALへの単一のエントリポイント」を作成する場合、それはコンテキストオブジェクトとどのように異なりますか?リポジトリがDALオブジェクトを取得して永続化するメカニズムを提供する場合、それはコンテキストオブジェクトとどのように異なりますか?
また、データコンテキストオブジェクトを管理するために作業単位パターンがリポジトリアクセスを一元化することを少なくとも1つの場所で読みましたが、これがなぜ重要なのかについても理解していません。
私はここで何かが欠けていると98.8%確信していますが、私の読書からはそれを見ませんでした。もちろん、私は正しい情報源を読んでいないかもしれません...:\
EntityFrameworkのDbContext
は、基本的にRepository(およびUnit of Work)に似ています。単純なシナリオでは、必ずしもそれを抽象化する必要はありません。
リポジトリの主な利点は、ドメインが無知であり、永続化メカニズムから独立している可能性があることです。レイヤーベースのアーキテクチャでは、依存関係はUIレイヤーからドメイン(または通常はビジネスロジックレイヤーと呼ばれます)を経由してデータアクセスレイヤーに到達します。これは、UIがBLLに依存し、BLL自体がDALに依存することを意味します。
より近代的なアーキテクチャ(ドメイン駆動設計やその他のオブジェクト指向アプローチによって伝播される)では、ドメインに外向きの依存関係があってはなりません。つまり、UI、永続化メカニズム、その他すべてはドメインに依存する必要があり、その逆ではありません。
リポジトリは、ドメイン内のインターフェイスを介して表されますが、ドメイン外の永続性モジュールに具体的に実装されます。このように、ドメインは抽象的なインターフェースのみに依存し、具体的な実装には依存しません。
これは基本的に、アーキテクチャレベルでのオブジェクト指向と手続き型プログラミングの違いです。
Ports and AdaptersakaHexagonal Architectureも参照してください。 ) 。
リポジトリのもう1つの利点は、さまざまなデータソースへの同様のアクセスメカニズムを作成できることです。データベースだけでなく、クラウドベースのストア、外部API、サードパーティアプリケーションなどにも使用できます。
「リポジトリ」という用語は、一般的に、「 リポジトリパターン 」がMartin Fowlerの著書 Patterns of Enterprise Application Architecture で説明されているように考えられていると思います。
リポジトリは、ドメインとデータマッピングレイヤーの間を仲介し、メモリ内のドメインオブジェクトコレクションのように機能します。クライアントオブジェクトは、クエリ仕様を宣言的に作成し、満足のためにリポジトリに送信します。オブジェクトは、オブジェクトの単純なコレクションと同様に、リポジトリに追加したり、リポジトリから削除したりできます。リポジトリによってカプセル化されたマッピングコードは、バックグラウンドで適切な操作を実行します。
表面的には、Entity Frameworkはこれらすべてを実現し、リポジトリの単純な形式として使用できます。ただし、リポジトリには、単なるデータレイヤーの抽象化以上のものが存在する可能性があります。
Eric Evansの著書 Domain Driven Design によると、リポジトリには次の利点があります。
- 永続オブジェクトを取得し、ライフサイクルを管理するための単純なモデルをクライアントに提示します
- これらは、アプリケーションとドメインの設計を永続化テクノロジー、複数のデータベース戦略、さらには複数のデータソースから切り離します。
- オブジェクトアクセスに関する設計上の決定を伝達します
- これらは、ユニットテスト(通常はメモリ内コレクションを使用)のために、ダミー実装を簡単に置き換えることができます。
最初のポイントは上記の段落とほぼ同じであり、EntityFramework自体がそれを簡単に実現できることは容易に理解できます。
EFが2番目のポイントも達成すると主張する人もいます。ただし、通常、EFは、各データベーステーブルをEFエンティティに変換し、それをUIに渡すために使用されます。データアクセスのメカニズムを抽象化している可能性がありますが、舞台裏でリレーショナルデータ構造を抽象化することはほとんどありません。
ほとんどデータ指向である単純なアプリケーションでは、これは重要なポイントではないように思われるかもしれません。しかし、アプリケーションのドメインルール/ビジネスロジックがより複雑になるにつれて、より多くのオブジェクト指向になりたいと思うかもしれません。データのリレーショナル構造に、ビジネスドメインにとって重要ではないが、データストレージの副作用である特異性が含まれていることは珍しくありません。このような場合、永続化メカニズムを抽象化するだけでなく、データ構造自体の性質も抽象化するだけで十分ではありません。 EFだけでは一般的にそれを行うのに役立ちませんが、リポジトリレイヤーは役に立ちます。
3番目の利点については、EFは(DDDの観点から)何もしません。通常、DDDはリポジトリを使用して、データの永続性のメカニズムを抽象化するだけでなく、特定のデータにアクセスする方法に関する制約を提供します。
また、トラバーサルで見つけるのに便利な永続オブジェクトのクエリアクセスも必要ありません。たとえば、PersonオブジェクトからPersonのアドレスを要求できます。そして最も重要なのは、AGGREGATEの内部にあるオブジェクトは、ルートからのトラバースを除いてアクセスが禁止されていることです。
つまり、データベースにAddressテーブルがあるという理由だけで、「AddressRepository」はありません。デザインがこの方法でAddressオブジェクトにアクセスする方法を管理することを選択した場合、PersonRepositoryは、デザインの選択を定義および適用する場所です。
また、DDDリポジトリは通常、ドメインデータのセットに関連する特定のビジネスコンセプトがカプセル化される場所です。 OrderRepositoryには、Ordersの特定のサブセットを返すOutstandingOrdersForAccountというメソッドが含まれる場合があります。または、CustomerリポジトリにPreferredCustomerByPostalCodeメソッドが含まれている場合があります。
Entity FrameworkのDataContextクラスは、リポジトリ抽象化レイヤーが追加されていないと、このような機能には適していません。これらは、DDDが仕様と呼ぶものに対して適切に機能します。仕様は、式に対してデータを評価して一致を返す単純なメソッドに送信される単純なブール式です。
4番目の利点については、データコンテキストの代わりに使用できる戦略があると確信していますが、リポジトリにラップすると非常に簡単になります。
「作業単位」に関して、DDDの本は次のように述べています。
トランザクション制御をクライアントに任せます。REPOSITORYはデータベースに挿入およびデータベースから削除しますが、通常は何もコミットしません。たとえば、保存後にコミットしたくなりますが、クライアントにはおそらく、作業単位を正しく開始してコミットするためのコンテキストがあります。 REPOSITORYが手を離すと、トランザクション管理が簡単になります。
そうです、これらの単純なケースでは、リポジトリはDAOの単なる別名であり、EFを別のデータアクセス技術に切り替えることができるという事実という1つの値しかもたらしません。今日はMSSQLを使用していますが、明日はクラウドストレージが必要になります。 OR EFの代わりにマイクロオームを使用するか、MSSQLからMySqlに切り替えます。
これらすべての場合において、リポジトリを使用することをお勧めします。アプリの残りの部分は、現在使用しているストレージを気にしないからです。
複数のソース(db +ファイルシステム)から情報を取得するという限られたケースもあります。リポジトリはファサードとして機能しますが、それでもDAOの別名です。
「実際の」リポジトリは、ドメイン/ビジネスオブジェクトを処理している場合にのみ有効です。ストレージを変更しないデータ中心のアプリの場合、ORMだけで十分です。
複数のデータソースがあり、一貫したコーディング戦略を使用してそれらにアクセスしたい場合に役立ちます。
たとえば、複数のEFデータモデルがあり、一部のデータはストアドプロシージャを備えた従来のADO.NETを使用してアクセスされ、一部のデータはサードパーティAPIを使用してアクセスされ、一部はWindowsNT4サーバー上にあるAccessデータベースからアクセスされます。ほうきクローゼット内のほこりの毛布。
ビジネスレイヤーやフロントエンドレイヤーがデータの送信元を気にしないようにする場合は、「Entity Frameworkデータ」にアクセスするのではなく、「データ」にアクセスするための汎用リポジトリパターンを構築します。
このシナリオでは、実際のリポジトリの実装は互いに異なりますが、それらを呼び出すコードは違いを認識しません。
あなたのシナリオを考えると、私は単に、データ層から返される必要のあるデータ構造(ドメインモデル)を表す一連のインターフェースを選択します。その場合、実装はEF、Raw ADO.Net、またはその他のタイプのデータストア/プロバイダーを組み合わせて行うことができます。ここでの重要な戦略は、実装が直接のコンシューマーであるドメインレイヤーから抽象化されることです。これは、ドメインオブジェクトの単体テストを行い、あまり一般的ではない状況で、データプロバイダー/データベースプラットフォームを完全に変更する場合に役立ちます。
依存性注入 を使用すると、ソリューションの疎結合が非常に簡単になるため、まだ使用していない場合は、 IOCコンテナー の使用を検討する必要があります。 利用できるものはたくさんあります 、個人的には Ninject が好きです。
ドメイン層は、すべてのビジネスロジック(問題のドメインのルールと要件)をカプセル化する必要があり、はMVC3Webアプリケーションで直接使用できます。特定の状況では、ドメイン層の上にある サービス層 を導入することは理にかなっていますが、これは必ずしも必要ではなく、単純なWebアプリケーションにとってはやり過ぎになる可能性があります。
考慮すべきもう1つのことは、単一のデータストアで作業することがわかっている場合でも、リポジトリの抽象化を作成することが理にかなっている可能性があるということです。その理由は、アプリケーションが必要とする機能があり、ORM du jourのパフォーマンスが悪い(パフォーマンス)か、まったくないか、ORMをニーズに合わせて曲げる方法がわからないためです。
よく考えられたリポジトリインターフェイスの背後にORMをラップしている場合は、必要に応じてさまざまなテクノロジを簡単に切り替えることができます。私のリポジトリでは、作業にEFを使用するメソッドと、PetaPocoや(gasp)ADO.netコードなどを使用するメソッドがあることは珍しくありません。リポジトリの抽象化により、これらの複雑さをクライアントコードに漏らすことなく、手元のジョブにぴったりのツールを使用できます。
多くの記事が「リポジトリ」と呼んでいるものには大きな誤解があると思います。そしてそれが、それらの抽象化がもたらす真の価値について疑問がある理由です。
私の意見では、純粋な形式のリポジトリはIEnumerableですが、あなたや多くの記事は「データアクセスサービス」について語っています。
私はそれについてブログを書きました ここ 。