38

私は BDD/DDD を調査しており、その結果、リポジトリ パターンの適切な実装を考え出そうとしています。これまでのところ、これを実装する最善の方法についてコンセンサスを見つけるのは困難でした。次のバリエーションに煮詰めようとしましたが、どれが最善のアプローチかはわかりません。

参考までに、バックエンドとしてNHibernateを使用してASP.MVCアプリケーションを構築しています。

public interface IRepository<T> {
        // 1) Thin facade over LINQ
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IQueryable<T> Find();
        // or possibly even
        T Get(Expression<Func<T, bool>> query);
        List<T> Find(Expression<Func<T, bool>> query);
}

public interface IRepository<T> {
        // 2) Custom methods for each query
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySku(string sku);
        IList<T> FindByName(string name);
        IList<T> FindByPrice(decimal price);
        // ... and so on
}

public interface IRepository<T> {
        // 3) Wrap NHibernate Criteria in Spec pattern
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}


public interface IRepository<T> {
        // 4) Expose NHibernate Criteria directly
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Remove(T entity);
        IList<T> FindAll();
        IList<T> Find(ICriteria criteria);
        // .. or possibly
        IList<T> Find(HQL stuff);
}

私の最初の考えは、

1) 効率の観点からは優れていますが、複雑になると問題が発生する可能性があります。

2) 非常に退屈なようで、非常に混雑したクラスになる可能性があります。

3) 前もってクエリを作成するのは難しく、より多くの作業が必要に思えますが、相互汚染は Specs レイヤーだけに限定されます。

4) あまり好きではありませんが、おそらく最も直接的な実装であり、複雑なクエリに対して最も効率的なデータベースですが、呼び出し元のコードに多くの責任が課せられます。

4

7 に答える 7

22

また、「上記のいずれでもない」アプローチに対する適切な議論もあります。

汎用リポジトリの問題は、システム内のすべてのオブジェクトが 4 つの CRUD 操作 (作成、読み取り、更新、削除) をすべてサポートすると想定していることです。しかし、複雑なシステムでは、一部の操作しかサポートしないオブジェクトが存在する可能性があります。たとえば、読み取り専用のオブジェクトや、作成されているが更新されていないオブジェクトがある場合があります。

IRepository インターフェイスを読み取り、削除などの小さなインターフェイスに分割することもできますが、すぐに面倒になります。

Gregory Young は、(DDD/ソフトウェア レイヤリングの観点から) 各リポジトリは、使用しているドメイン オブジェクトまたは集計に固有の操作のみをサポートする必要があるという優れた議論を行っています。これは、汎用リポジトリに関する彼の記事です。

別のビューについては、この Ayendeブログ投稿を参照してください。

于 2009-09-12T00:14:39.723 に答える
10

それらはすべて良い選択肢だと思います(nhibernateに縛られたくない場合はおそらく4つを除いて)、そしてあなたはあなたの現在の努力に基づいてあなた自身で決定を下すために賛否両論をよく分析しているようです。これで自分を激しく殴らないでください。

私は現在、2と3の混合物に取り組んでいます。

public interface IRepository<T> 
{
        ...
        IList<T> FindAll();
        IList<T> FindBySpec(ISpecification<T> specification);
        T GetById(int id);
}

public interface ISpecificRepository : IRepository<Specific> 
{
        ...
        IList<Specific> FindBySku(string sku);
        IList<Specific> FindByName(string name);
        IList<Specific> FindByPrice(decimal price);
}

また、(Tの)リポジトリ基本クラスもあります。

于 2009-09-11T02:43:39.913 に答える
6

私たちが行っていることの1つは、すべてのリポジトリのニーズが異なるため、インターフェイスのコレクションを作成していることです。

public interface IReadOnlyRepository<T,V>
{
   V Find(T);
}

この例では、読み取り専用リポジトリはデータベースから取得します。T、Vの理由は、Vがリポジトリによって返されるものを表し、Tが渡されるものを表すため、次のようなことができます。

public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer>
{
    public Customer Find(int customerId)
    {
    }

    public Customer Find(string customerName)
    {
    }
}

追加、更新、削除用に別々のインターフェースを作成することもできます。このように、私のリポジトリが動作を必要としない場合、それは単にインターフェースを実装しません。

于 2009-09-11T03:58:33.960 に答える
1

私は 1 の bif ファンです。なぜなら、Find メソッドの IQueryable<> 戻り値に適用できるよりも、フィルターとページング拡張メソッドを作成できるからです。拡張メソッドをデータ レイヤーに保持し、ビジネス レイヤーでオンザフライで構築します。(確かに、完全に純粋ではありません。)

もちろん、システムが安定したら、同じ拡張メソッドを使用して特定の Find メソッドを作成し、Func<> を使用して最適化するオプションがあります。

于 2009-09-11T03:11:46.587 に答える
1

Linq で NH を使用する場合、リポジトリは次のようになります。

session.Linq<Entity>()

仕様は、次のものを扱います。

IQueryable<Entity>

必要に応じてすべてをファサードにすることもできますが、抽象化を抽象化するのは非常に平凡な作業です。

シンプルイズグッド。ええ、NH はデータベースを処理しますが、さらに多くのパターンを提供します。DAL 以外を NH に依存させることは、決して罪ではありません。

于 2009-09-11T14:55:10.010 に答える
1

それはあなたのニーズ次第だと思います。リポジトリについては、使用を検討している他の設計パターンと併せて考えることが重要です。最後に、リポジトリに何を期待するかによって大きく異なります (リポジトリを使用する主な理由は何ですか)。

厳密なレイヤーを作成する必要がありますか (たとえば、将来的に NHibernate を Entity Framework に置き換える必要があります)? 特にリポジトリメソッドにテストを書きたいですか?

リポジトリを作成する最良の方法はありません。いくつかの方法があり、それは間違いなくあなた次第です。あなたのニーズにとって最も実用的なものは何ですか.

于 2015-09-07T18:17:43.130 に答える
0

リポジトリを枯らす

LosTechies の Jimmy Bogard による関連記事

http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx

また、バージョン #2 は実際には DOA パターンであり、リポジトリではないことを示唆するいくつかのコメントを含む別の簡単な記事です。

http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html

于 2009-09-11T16:21:28.633 に答える