web-dev-qa-db-ja.com

リポジトリへまたはリポジトリへ

ドメインドリブンデザインについて最初に知ったとき、データベースに対する穴居人のようなSQLクエリを投げたクールな子供たちにとってかつては一流であると思われていたリポジトリと作業単位パターンも紹介されました。 [〜のようなORMsのために、それらがもはや必要ではないように見えるということを、そのトピックに深く入れば深くなるほど学びました。 #〜] ef [〜#〜]およびNHibernateは、作業単位とリポジトリの両方を、セッションまたはコンテキストと呼ばれる1つのAPIに実装します。

今、私は何をすべきかわかりません。リポジトリするかしないか。このようなリークの多い抽象化は複雑すぎるものだけであり、データアクセスを簡略化するものは何も追加しないという主張を本当に理解していますが、アプリケーションのあらゆる側面を結合するのは適切ではないと感じています。 エンティティフレームワーク。通常、私はいくつかの簡単なガイドラインに従います:

  1. ドメイン層は、エンティティ、サービス、リポジトリを含むシステムの中心です...
  2. インフラストラクチャレイヤーは、インフラストラクチャ関連のドメインインターフェースの実装を提供します。ファイル、データベース、プロトコル。
  3. アプリケーション層は、物事を結び付け、すべてをオーケストレーションするコンポジションルートをホストします。

私のソリューションは通常、次のようになります。

Domain.Module1
Domain.Module2
    IModule2Repo
    IModule2Service
    Module2
Infrastructure.Persistence
    Repositories
        EntityFrameworkRepositoryBase
MyApp
    Boostrapper
        -> inject EntityFrameworkRepositoryBase into IRepository etc.

IRepository<'T>を使用して、ドメインレイヤーをクリーンに保ちます。これは、データへのアクセス方法を教えてくれる他の何にも依存しないドメインの問題でもあります。データアクセスを必要とするIModule2Serviceの具体的な実装を作成する場合、DbContextを注入する必要があり、これによってインフラストラクチャレイヤーに直接結合します。 (Visual Studioプロジェクトに移行すると、循環依存関係のため、これは本当にトリッキーになる可能性があります!

追加depositories作品の代替品? CQRS?純粋なインフラストラクチャフレームワークをどのように抽象化しますか?

10
Acrotygma

エンジニアリングは妥協のすべてです。ソフトウェア開発も同様です。今のところ、もっと簡単なのはORMを直接操作することだけです。しかし、あなたが言ったように、それはあなたを特定の永続化フレームワークにロックするかもしれません。

したがって、「永続性からコードを分離する価値がある追加の複雑さですか」と自問する必要があります。持続性からコードを分離したいと人々が言うのを聞くたびに、「あなたのキャリアの中で、持続性フレームワークを何回変更しましたか?」

リポジトリに関して私が目にする問題は、一般的な変更が難しくなることです。例えば。集計をクエリする新しい方法を追加します。そして、彼らは珍しい変更を(おそらく)より簡単にします。例えば。リポジトリの実装の変更。

次に、ユニットテストの引数もあります。「永続性フレームワークでは、データベースをメモリ内またはローカルでモックすることができない場合、フレームワークを使用する価値はまったくありません。」

4
Euphoric

私はプロリポジトリですが、一般的なリポジトリパターンから離れました。代わりに、リポジトリをそれらが提供するビジネス機能に合わせます。リポジトリはORMを抽象化することを目的としていません。これは私が変更することを期待するものではないため、リポジトリを細かくしすぎることを避けます。 (つまり、CRUD)代わりに、私のリポジトリは2〜3つの主要な目的を果たします。

  • データ検索
  • データ作成
  • 完全削除

データを取得する場合、リポジトリは常に_IQueryable<TEntity>_を返します。データ作成の場合、TEntityを返します。リポジトリーは、一時削除パターンを使用するシステムの許可「アクティブ」状態、履歴データを使用するシステムの「現在の」状態など、私の基本レベルのフィルタリングを処理します。データの作成は、必要な参照が解決されて関連付けられていること、およびエンティティーがセットアップされて準備ができていることを確認することのみを担当します。

データの更新は、問題のエンティティを処理するビジネスロジックの責任です。これには、検証ルールなどを含めることができます。私はそれをリポジトリメソッドにカプセル化しようとしません。

ほとんどのシステムでの削除はソフト削除であるため、データの更新に該当します。 (IsActive = false)完全削除の場合、これはリポジトリ内の1行になります。

なぜリポジトリなのか?テスト能力。確かに、DbContextはモックできますが、_IQueryable<TEntity>_を返すクラスをモックする方が簡単です。彼らはまた、UoWパターンでニースを再生します。個人的には、MehdimeのDbContextScopeパターンを使用して、必要なレベル(つまり、MVCのコントローラー)で作業単位をスコープアウトし、コントローラーとヘルパーサービスクラスが参照を渡さなくてもリポジトリを利用できるようにします。周辺のUoW/dbContext。 IQueryableを使用すると、リポジトリに多くのラッパーメソッドが必要なくなり、コードでデータの消費方法を最適化できます。たとえば、リポジトリは「Exists」や「Count」などのメソッドを公開したり、データのサブセットが必要な場合にエンティティを他のPOCOでラップしたりする必要はありません。彼らは、あなたが必要とするかもしれないし必要としないかもしれない関連データのための熱心な読み込みオプションを処理する必要さえありません。 IQueryableを渡すことにより、呼び出しコードは次のことができます。

_.Any()
.Count()
.Include() // Generally avoided, instead I use .Select()
.Where()
.Select(x => new ViewModel or Anon. Type)
.Skip().Take()
.FirstOrDefault() / .SingleOrDefault() / .ToList()
_

非常に柔軟性があり、テストのP.O.V.私のモック化されたリポジトリーは、単に、入力されたエンティティー・オブジェクトのリストを返す必要があります。

一般的なリポジトリに関しては、テーブルごとにリポジトリが作成されると、コントローラー/サービスが1つのビジネスアクションを実行するために複数のリポジトリへの参照になってしまうので、大部分はこれらから離れました。ほとんどの場合、これらのリポジトリの1つまたは2つだけが実際に書き込み操作を行っています(ナビゲーションプロパティを適切に使用している場合)。残りは読み取りでそれらをサポートしています。 5つまたは6つの異なるリポジトリにアクセスするのではなく、注文の読み取りと作成、および関連するルックアップなど(軽量の顧客オブジェクト、製品など)の読み取りが可能な注文の作成時に参照できるOrdersRepositoryのようなものが欲しいです。それはDNRY純粋主義者に違反するかもしれませんが、それに対する私の議論は、リポジトリの目的は関連する参照を含む注文の作成に役立つことであるということです。製品を取得するために_Repository<Product>_に移動する必要はありません。注文の基礎として、少数のフィールドを持つエンティティのみが必要です。私のOrderRepositoryには、_IQueryable<ProductSummary>_を返す.GetProducts()メソッドが含まれている可能性があります。これは、アプリケーションのニーズのさまざまな領域を試行して処理するための複数の "Get"メソッドを持つ_Repository<Product>_よりも優れていると思います。および/またはいくつかの複雑なパスインフィルタリング式。

追跡、テスト、調整が簡単な、より単純なコードを選びます。それは悪い方法で悪用される可能性がありますが、悪用できない方法でコードを「ロックダウン」して失敗し、それから何かであるよりも、悪用が簡単に見つけて修正できるようなものが欲しいです最終的にクライアントが実行するためにクライアントが支払うものを実際に実行するための悪夢。 :)

3
Steve Py