リポジトリパターンを使用して、一般的な使用のために、データセット(テーブル)のIQueryableを返すことは適切ですか?
これは多くの場合に非常に便利です。特に、インターフェイスを活用する外部ライブラリ、たとえば、UI要素をソート/フィルタリングしてバインドするプラグインを使用する場合に便利です。
ただし、IQueryableを公開すると、デザインにエラーが発生しやすくなる場合があります。これと遅延読み込みの誤った使用を組み合わせると、パフォーマンスに重大な影響を与える可能性があります。
一方、使用方法ごとにアクセスメソッドを用意することは冗長であり、多くの作業(単体テストなどを考慮)もあるようです。
Mark Seemannは、このテーマについて優れたブログ投稿 IQueryable is Tight Coupling を公開しています。彼は最後の部分でそれをうまくまとめています(私の強調):
これはすべて理論的な演習だと思うかもしれませんが、実際には重要です。 Clean Codeを作成するときは、APIの機能が明確になるようにAPIを設計することが重要です。
このようなインターフェースは誤った保証をします:
public interface IRepository
{
IQueryable<T> Query<T>();
}
LSPとPostelの法則によれば、返されたインスタンスに対して(どんなに複雑であっても)クエリ式を記述できることが保証されているようで、常に機能します。
実際には、これは決して起こりません。
そのようなインターフェースを定義するプログラマーは常に特定のORMを念頭に置いており、暗黙のうちにその特定のORMに対して安全であることがわかっている境界内にとどまる傾向があります。これは漏れやすい抽象化です。
特定のORMを念頭に置いている場合は、それについて明確に説明してください。インターフェースの背後に隠さないでください。ある実装を別の実装に置き換えることができるという錯覚を引き起こします。実際には、それは不可能です。イベントストアを介して実装を提供しようとしていると想像してください。
ケーキは嘘です。
ORMのようなEntity Frameworkは、リポジトリと作業単位パターンの実装です。それらを別のものにラップする必要はありません。
これについてはコンセンサスはありません。私の意見と経験では、リポジトリは特定の用途を持つオブジェクトを返す必要があります。少なくとも、DDDでEric Evensによって定義されたリポジトリパターンを使用する場合。リポジトリは、ビジネスロジック、永続性、およびファクトリを接続する「ブリッジ」です。
より永続的にアクセスしたい場合は、ゲートウェイパターンを探している可能性があります。
ただし、ここで言うことから、その持続性への露出を隠して、プロキシパターンが便利になるようにします。