最近、リポジトリパターンをORMと組み合わせて使用することはお勧めしません。私の理解から、これは、SQLデータベースを介してそれらが提供する抽象化が、パターンに含まれるには漏れやすいためです。
これについていくつか質問があります。
ORMを切り替える場合はどうしますか?リポジトリに含まれていない場合、アプリケーションにORM固有のコードが含まれます。
ORMを使用しておらず、データアクセスにADO.NETを使用してオブジェクトデータを自分で生成している場合でも、リポジトリパターンは有効ですか?
ORMを使用するがリポジトリパターンを使用しない場合、どこで一般的に使用されるクエリを保持しますか?各クエリをクラスとして表現し、インスタンスを作成するクエリファクトリのようなものを用意するのは賢明でしょうか?
1)本当ですが、どのくらいの頻度でORMを切り替えますか?
2)私はそう思います。ORMコンテキストはリポジトリのようなものであり、クエリの作成、データの取得、マッピングなどに関連する多くの作業を隠します。ORMを使用しない場合でも、そのロジックはどこかに住んでいる必要があります。しかし、それがWordの最も厳密な意味でのリポジトリパターンと見なされるかどうかはわかりません...
3)クエリのカプセル化はよく目にするものですが、通常はテスト/スタブの目的のためです。それ以外は、アプリケーションのさまざまな部分でクエリを再利用するときは注意が必要です。それは、n回変更される可能性がある何かへの依存関係を作成するリスクがあるためです(nはクエリを使用する場所の数です)。
1)ORMを切り替える場合はどうしますか。リポジトリに含まれていない場合、アプリケーションに特定のORMコードがあります。
私はまだ会社が突然、データアクセステクノロジーの切り替えを決定する立場にはありませんでした。これが発生した場合、いくつかの作業が必要になります。私はインターフェースを介してデータアクセス操作を抽象化する傾向があります。リポジトリはこれを解決する1つの方法です。
次に、データアクセス層を具体的に実装するための別のアセンブリを用意します。たとえば、私は持っているかもしれません:
Company.Product.Data
およびCompany.Product.Data.EntityFramework
アセンブリ。 Entity Frameworkのデータアクセスロジックの具体的な実装が別の場合、最初のアセンブリは純粋にインターフェイスに使用されます。
2)ORMを使用せず、ADO.netを使用してデータアクセスとオブジェクトデータの入力を自分で行っている場合でも、リポジトリパターンは有効ですか?
どのパターンが有効であるかを決めるのはあなた次第だと思います。プレゼンテーション層でリポジトリパターンを使用しました。心に留めておくべきことは、人々は責任をリポジトリに投入することを好むということです。あなたがそれを知る前に、あなたのリポジトリクラスはあらゆる種類のことを踊り、歌い、そして行うでしょう。あなたはこれを避けたいです。
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でソリューションを参照し、特定のコンポーネントがどのような責任を負っているかを即座に確認できます。代わりにリポジトリパターンを使用することに決めた場合は、責任を果たそうとする各リポジトリクラスを調べる必要があります。
免責事項:以下は、上記のパターン(リポジトリ)についての私の理解と短い経験に基づいています。私はそれを間違っているかもしれません...実際、私は私がそれを間違っているとかなり前向きです:)したがって、これは答えの試みですが、変装の質問でもあります。
私は、Repositoryパターンを使用して、ほとんどの場合ORMであるデータアクセス層を抽象化しています。これは、これまでのLINQ to SQLおよびEFのCreate、Read、Update、Delete、および実装クラスのメソッドを備えた汎用インターフェイスです。ディスク上のXMLファイルに書き込む実装を作成することができます(それを使用してできることの単なる例です)。 ORMでサポートされているため、作業ユニットは実装していません。必要に応じて、実装することもできます。これまでのところ、それは私に素晴らしい分離を与えているので、私はこの方法が好きです。これ以上の選択肢はありません。
あなたの質問に答えるには:
別の例を示すと、Umbracoのスタッフは、DIコンテナーを抽象化して、別のものに切り替えたい場合があるかもしれません。
ORMがLINQ、熱心なロードなどの柔軟性を提供する場合、追加のレイヤーの背後にそれを隠さないでしょう。
生のsql(マイクロ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を非表示にすることを選択した場合、すべての候補者が共通して持っている機能のみを使用できます。
例えば。 ormYはそれらを処理できないため、エンティティで_Dictionary<string, Entity>
_プロパティを使用できません。
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が使用されていると仮定すると、クラスラッパーはIMHOを過剰に使用します。より良い方法は拡張メソッドです
_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);
}
_
複数の場所で使用されている(または潜在的な可能性がある)コードで十分に複雑な(エラーが発生しやすい)コードは、中央の場所に抽出する必要があります。