12

小さなプロジェクトでIRepositoryパターン(重要な場合はNHibernateに裏打ちされたもの)を使用したいと考えています。ドメインは単純なものであり、意図的にIRepositoryパターンの理解に集中できるようになっています。唯一のドメインクラスは、、、、およびMovieのプロパティを持ちYearます。私の意図は、プロパティが前述のタイプの基準に一致する映画を「取得」することです。GenreTitle

規則はIRepository、次のような一般的なインターフェイスを備えているようです。

public interface IRepository<T>
{
    T Get(int id);
    T[] GetAll();
    void Add(T item);
    void Update(T item);
    void Delete(T item);
}

基本実装の場合:

public abstract class Repository<T> : IRepository<T>
{
    public T Get(int id) { ... }
    public T[] GetAll() { ... }
    public void Add(T item) { ... }
    public void Update(T item) { ... }
    public void Delete(T item) { ... }
}

次に、ドメイン固有のインターフェースを作成します。

public interface IMovieRepository
{
    Movie[] GetByGenre(Genre genre);
    Movie[] GetByYear(int year);
    Movie[] GetByTitle(string title);
}

Repository基本クラスも拡張する実装では、次のようになります。

public class MovieRepository : Repository<Movie>, IMovieRepository
{
    public Movie[] GetByGenre(Genre genre) { ... }
    public Movie[] GetByYear(int year) { ... }
    public Movie[] GetByTitle(string title) { ... }
}

NHibernateを使用して、基本クラスと具象クラスに必要な実装を追加する必要がありますが、この設定で正しい方向に進んでいるかどうかを知りたいと思います。

複数のドメインクラスが関係している場合は目立たなくなりますが、1つのドメインクラスだけでかなりのオーバーヘッドがあるようです。今、私はそれをシンプルに保とうとしているので、コンセプトを突き止めることができます。

4

3 に答える 3

6
  1. を返さないようにしてくださいarrayIEnumerable<T>ICollection<T>またはを使用するとIList<T>、コードがさらに疎結合になります。

  2. あなたの IMovieRepository インターフェイス。このリポジトリには CRUD が含まれています。だから作る

IMovieRepository : IRepository<Movie> {}

これによりMovieRepository、インターフェイスが正しく実装されるため、クラスは変更されません。後で実装を変更したい場合は、クラスを分離することができます。

最後に。これは、いずれかの方法で問題ありません。特殊な機能を持っているので、それに合わせてリポジトリを特殊化しました。

1 つのリポジトリ クラスを使用して、必要なクエリを渡す方法は他にもあります。これを仕様パターンと呼びます。私はレポートhttp://whiteboardchat.codeplex.comでコードプレックスにあるこれを使用するプロジェクトを行いました

もう1つの方法は、基準を渡す方法を用意することです。Sharp Architecture と呼ばれるオープン ソース プロジェクトがあり、これがコード化されていると思います。

お役に立てれば

于 2010-07-31T19:28:18.857 に答える
2

あなたは、運輸会社のリソース計画の本番ソリューションで使用しているリポジトリに近いと思います (NHibernate も使用しています)。配列の代わりに IEnumerables /IList を使用することについて dbones に同意します - .ToArray() を何度も書くことになります:-)。

あなたが考慮するかもしれないいくつかのこと:

抽象リポジトリから継承する代わりに、継承よりも構成を優先します。非抽象化して 'ctor に注入し、呼び出しを委任します。これにより、特定の状況で設計がより堅牢になります (たとえば、クエリのみのリポジトリなど)。 ) そうすれば、抽象リポジトリをインスタンス化可能にするオプション (それは言葉ですか?) と、それをすべてのリポジトリで共有するかどうかを制御するオプションもあります。

その点をフォローアップ - ジェネリック インターフェイスから継承するのではなく、ジェネリック メソッドを持つようにベース リポジトリを変更することをお勧めします。

public class Repository
{
    public void Add<T>(T entity)
    {
        using(var session = GetSession())
        using(var tx = session.BeginTransaction())
        {
             session.Save(entity)
             //Transaction handling etc.
        }
    }
    .... //repeat ad nasseum :-)
}

特定のリポジトリに ISession へのアクセスを許可したい場合があります。これにより、クエリを作成して熱心な/遅延フェッチを制御できる柔軟性が大幅に向上し、NHibernate などを最大限に活用できます。

public class Repository
{
    public IList<T> WrapQueryInSession<T>(Func<ISession,IList<T> query)
    {
        using(var session = GetSession())
        using(var tx = session.BeginTransaction())
        {
             var items = query(session);
             //Handle exceptions transacitons etc.
             return items;
        }
     }
 }

使用法:

public class MovieRepository : IMovieRepository
{
    private Repository _repository;
    public MovieRepository(Repository repository)
    {
        _repository = repository;
    }
    public IList<Movie> GetByYear(int year)
    {
        Func<ISession, IList<Movie> query = session =>
        {
            var query = session.CreateQuery("from Movie"); //or
            var query = session.CreateCriteria("from Movie"); //or
            var query = session.Linq<Movie>();
            //set criteria etc.
            return query.List<Movie>(); //ToList<Movie>() if you're using Linq2NHibernate
        }:
        return _repository.WrapQueryInSession(query);
    }
}

何か問題が発生した場合は、メソッドに bool の戻り値を設定することもできます。また、呼び出し元のコードで意味のあるエラーが発生した場合は、out IEnumerable を設定することもできます。

しかし、全体として、これらは私の使用法によりよく準拠するために時間をかけて追加した単なるちょっとした情報であり、完全にオプションであり、考える材料に過ぎません :-)。あなたは正しい道を進んでいると思います。コードに大きな問題は見られません。

これが理にかなっていることを願っています:-)

于 2010-07-31T20:11:59.313 に答える
0

参考までに、選択した ORM に LINQ プロバイダーがある場合 (および NH に LINQ プロバイダーがある場合) は、コレクションに非常に似たクエリ可能なリポジトリを試すことができます。

public interface IRepository<T> : ICollection<T>, IQueryable<T>

私は自分のサイトでそれについていくつか書いています:リポジトリまたは DAO?: リポジトリ それはあなたの構造に似ています (コレクションが CRUD もサポートしているという理由だけで)、私が試みるアプローチは、必ずしも認識していないコードを持つことができることを意味しますICollectionまたはインターフェイスに対してプログラムできるため、リポジトリを処理しIQueryableます...

于 2010-07-31T20:43:30.683 に答える