リポジトリパターンを使用する場合


20

最近、リポジトリパターンをORMと組み合わせて使用​​するのは良い習慣ではないことを読みました。私の理解から、これはSQLデータベース上で提供する抽象化がパターンに含まれるには漏れやすいためです。

これについていくつか質問があります。

  1. ORMを切り替えたい場合はどうしますか?リポジトリに含まれていない場合、アプリケーションにORM固有のコードが含まれます。

  2. ORMを使用せず、データアクセスとオブジェクトデータの入力にADO.NETを使用している場合、リポジトリパターンはまだ有効ですか?

  3. リポジトリパターンではなくORMを使用する場合、よく使用されるクエリはどこに保存しますか?各クエリをクラスとして表現し、インスタンスを作成するための何らかのクエリファクトリを用意するのが賢明でしょうか?


1
1)動作が異なるためORMをスワップアウトすることはできません。両方がlinqをサポートしていても、アプリケーションが動作しなくなるほど動作が異なります。例えば遅延ロードの挙動、汚い追跡、ゴーストプロキシなど。...テストするためで-MEMの実装のためのORM入れ替えることができるようにすることがいいです
ロジャー・ヨハンソン

何それの価値については、リポジトリ/ ORMの議論の私の感想はここにある:stackoverflow.com/questions/13180501/...
エリック・キング

どこが悪い習慣だと読んだのですか?
デイブヒリアー

回答:


3

1)本当ですが、ORMを切り替える頻度はどれくらいですか?
2)ORMコンテキストは一種のリポジトリであり、クエリの作成、データの取得、マッピングなどを含む多くの作業を隠すため、そう言います。ORMを使用しない場合、そのロジックはまだどこかに存在する必要があります。しかし、それが単語の最も厳密な意味でリポジトリパターンとして適格であるかどうかはわかりません...
3)クエリのカプセル化は頻繁に見られるものですが、それは通常テスト/スタブの目的のためです。それ以外は、アプリケーションのさまざまな部分でクエリを再利用するときは注意が必要です。なぜなら、n回(nはクエリを使用する場所の数)を変更する可能性のあるものに依存関係を作成するリスクがあるからです。


1
1)間違った質問をしている。どのくらいの頻度でもかまいませんが、一度だけあればよいのです。使用可能なORMオプションの数を考えると、既に使用しているものよりも優れたオプションがあるかもしれません。質問は次のとおりです。リポジトリは、素晴らしい抽象化を提供します。私はそこにいましたが、そもそもそのような抽象化をしたいと思います。
devnull

3
@devnull私は同意しません。せいぜい一度しか起こらないなら、私はそれを受け入れられるリスクだと考えます。あなたが間違った選択をすることを恐れるなら、1つにコミットする前にもっと実験してください。理論的には、このような抽象化はいいように思えますが、実際には、ORMのAPIのかなりの部分を再作成することになります。私にとって、それは無駄な努力、冗長なコード、そしてあなた自身が維持し保証しなければならないコードです。また、ORMを切り替えても、アプリケーション全体に影響することはありません。ドメイン境界を配置することを学びます。
ステファンビリエット

リポジトリの理由はORMの変更だけではありません。アプリケーションに[分散]キャッシュを導入する必要がある場合-すべての変更はリポジトリで行われ、データアクセスレイヤーの変更によりBLは変更されません。
ヴァレリー

ほとんどの場合、分散キャッシュはORMに組み込まれませんか?
user1450877

ORMに依存すると思います。NHibernateやEFよりも軽いORMを選択することができます。
ヴァレリー

2

1)ORMを切り替える場合はどうしますか。リポジトリに含まれていない場合、アプリケーションに特定のORMコードが含まれます。

私はまだ会社が突然データアクセステクノロジーを切り替えることを決めた立場にありませんでした。これが発生した場合、いくつかの作業が必要になります。私は、インターフェースを介してデータアクセス操作を抽象化する傾向があります。リポジトリはこれを解決する1つの方法です。

その後、データアクセス層の具体的な実装用に別のアセンブリを作成します。たとえば、私が持っている可能性があります:

Company.Product.DataおよびCompany.Product.Data.EntityFrameworkアセンブリ。別のエンティティアセンブリがEntity Frameworkのデータアクセスロジックの具体的な実装である場合、最初のアセンブリはインターフェイスのみに使用されます。

2)ORMを使用せず、データアクセスとオブジェクトデータの入力にADO.netを使用している場合、リポジトリパターンはまだ有効ですか?

どのパターンが有効かどうかを決めるのはあなた次第だと思います。プレゼンテーションレイヤーでリポジトリパターンを使用しました。心に留めておくべき1つのことは、人々がリポジトリに責任を投げることを好むということです。あなたがそれを知る前に、あなたのリポジトリクラスは踊り、歌い、あらゆる種類のことをします。これを避けたい。

GetAll、GetById、Update、Deleteの責任を持つことから始めたリポジトリクラスを見てきましたが、これは問題ありません。プロジェクトが完了するまでに、その同じクラスには数十個のメソッド(責任)がありました。たとえば、GetByForename、GetBySurname、UpdateWithExclusions、その他あらゆる種類のものです。

これは、クエリとコマンドが作用する場所です。

3)リポジトリパターンではなくORMを使用する場合、よく使用されるクエリはどこに保存しますか。各クエリをクラスとして表現し、インスタンスを作成する何らかのクエリファクトリを用意するのが賢明でしょうか?

リポジトリの代わりにクエリとコマンドを使用することは非常に良い考えだと思います。私は次のことを行います:

  • クエリのインターフェイスを定義します。これは、単体テストに役立ちます。例えばpublic interface IGetProductsByCategoryQuery { ... }

  • クエリの具体的な実装を定義します。これらは、選択したIoCフレームワークを介して注入できます。例えばpublic class GetProductsByCategoryQuery : IGetProductsByCategoryQuery

リポジトリを数十の責任で汚染する代わりに、クエリを名前空間にグループ化するだけです。たとえば、上記のクエリのインターフェイスは次の場所にあります。Company.SolutionName.Products.Queries実装は次の場所にあります。Company.SolutionName.Products.Queries.Implementation

データの更新または削除に関しては、コマンドパターンを同じ方法で使用します。

プロジェクトが完了する前に、数十のクラスと名前空間を持つことに同意しないと言う人もいます。はい、します。私の考えでは、選択したIDEのソリューションを参照して、特定のコンポーネントがどのような責任を負うかをすぐに確認できるので、良いことです。代わりにリポジトリパターンを使用することにした場合は、各リポジトリクラスの内部を調べて、その責任を解決する必要があります。


汎用関数の代わりにコマンドを使用するというアイデアが好きです。データアクセスのコンテキストでそれらを実装する方法に関する詳細はどこで参照できますか?
ankush981

1

免責事項:以下は、前述のパターン(リポジトリ)についての私の理解と簡単な経験に基づいています。私はそれを間違っているかもしれません...実際、私はそれを間違っているとかなり肯定的です:)。したがって、これは回答の試みですが、変装した質問でもあります。

Repositoryパターンを使用して、ほとんどの場合ORMであるデータアクセスレイヤーを抽象化します。これは、これまでのLINQ to SQLおよびEFの作成、読み取り、更新、削除、および実装クラスのメソッドを備えた汎用インターフェイスです。ディスク上のXMLファイルに書き込む実装を作成できました(これを使用してできることの単なる例です)。ORMでサポートされているため、作業単位を実装していません。必要であれば、おそらく実装できます。これまでのところ、それは私に素晴らしい分離を与えたので、私はこの方法が好きです。より良い代替手段がないと言っているのではありません。

質問に答えるには:

  1. 好むと好まざるとにかかわらず、変化が起こります。多数のアプリケーションを作成し、それらを維持する時間が来たが、それが現在のORMで作業するのが苦痛であり、それを変更したい場合は、そのような抽象化を行ったことを称賛します。リポジトリであれ、他のパターンやコンセプトであれ、使いやすいものなら何でも使用してください。
  2. はい、データアクセスを分離するために使用する限りです。前述のように、データをフラットファイルに書き込む実装を作成できます。
  3. リポジトリを使用して、よく使用するクエリとクエリオブジェクトを保持します(微調整したいクエリがある場合)(あまり多くはありません)。

別の例を挙げると、Umbracoのスタッフは、他の何かに切り替えたい場合に備えて、DIコンテナーを抽象化しました。


0

ORMがLINQ、Eager Loadingなどの柔軟性を提供する場合、余分なレイヤーの後ろにORMを隠しません。
raw sql(micro ORM)が関係する場合は、とにかく「クエリごとのメソッド」を使用して再利用性を実現し、リポジトリパターンを適切に適合させる必要があります。

What do you do if you want to switch out ORMs? 
You would have ORM specific code in your application if you do not contain it in a repository.

なぜ切り替える必要があるのですか?
必要な機能のほとんどを備えたものを使用する必要があります。ormXの新しいリリースが新しい機能をもたらし、現在の機能よりも優れていることが判明する可能性がありますが、...
ormを非表示にすることを選択した場合、すべての候補者が共通して持つ機能のみを使用できます。
たとえばDictionary<string, Entity>、ormYはプロパティを処理できないため、エンティティでプロパティを使用できません。

LINQと仮定すると、ORMスイッチの大半は、単にライブラリの参照を切り替えると交換され、使用されているsession.Query<Foo>()context.Foos、それがコンパイルされるまでまたは類似。退屈なタスクですが、抽象化レイヤーをコーディングするよりも時間がかかりません。

Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?

はい。コードは再利用可能である必要があります。つまり、SQLの構築、オブジェクトの実体化などを1つの場所(別個のクラス)に配置する必要があります。クラスを「XRepository」と呼び、そこからインターフェースを抽出することもできます。

If you use an ORM but not the repository pattern where do you keep commonly used queries? 
Would it be wise to represent each query as a class and have some sort of query factory to create instances?

LINQが使用されていると仮定すると、クラスラッパーはやり過ぎです。より良い方法は拡張メソッドです

public static IQueryable<T> Published<T>(this IQueryable<T> source) where T : Page
{
    // at some point someone is going to forget to check that status
    // so it makes sense to extract this thing
    return source.Where(x => x.Status == Status.Published && x.PublishTime <= DateTime.UtcNow);
}

複数の場所で使用されている(またはその可能性がある)コードが十分に複雑(エラーが発生しやすい)な場合は、中央の場所に抽出する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.