36 votes

La meilleure façon de mettre en œuvre un Modèle de Référentiel?

J'ai été d'explorer BDD/DDD et comme une conséquence essayer de venir avec une bonne mise en œuvre du modèle de Référentiel. Jusqu'à présent, il a été difficile de trouver un consensus sur la meilleure façon de le mettre en œuvre. J'ai essayé de la faire bouillir pour la suite de variations, mais je n'en suis pas sûr quelle est la meilleure approche.

Pour référence, je suis en train de construire un ASP.Application MVC avec NHibernate comme un back-end.

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);
}

Mes premières pensées sont que

1) est grande à partir d'un point de vue, mais je peut avoir des ennuis comme les choses deviennent plus compliquées.

2) semble très fastidieux et pourrait se retrouver avec un très encombré de la classe, mais sinon, il offre un haut degré de séparation entre mon domaine de la logique et de la couche de données que j'aime.

3) semble difficile à l'avant et plus de travail pour écrire des requêtes, mais les limites de la contamination croisée juste les Spécifications de la couche.

4) j'ai le moins aimé, mais peut-être la plus directe de mise en œuvre et, éventuellement, la plupart de la base de données efficace pour les requêtes complexes, mais elle met beaucoup de responsabilité sur le code appelant.

22voto

dthrasher Points 10641

Il y a aussi un bon argument pour un "none of the above" approche.

Le problème avec des référentiels génériques, c'est que vous êtes faisant l'hypothèse que tous les objets dans votre système prend en charge tous les quatre opérations CRUD: Create, Read, Update, Delete. Mais dans les systèmes complexes, vous aurez probablement avoir des objets qui prennent en charge uniquement quelques-uns des opérations. Par exemple, vous pourriez avoir des objets qui sont en lecture seule, ou des objets qui sont créés mais jamais mis à jour.

Vous risquez de casser l'interface IRepository en petits interfaces, pour Lire, Supprimer, etc. mais qui est malpropre assez rapidement.

Gregory Jeune qui fait un bon argument (à partir de DDD / logiciel de superposition point de vue) que chaque dépôt doit prendre en charge uniquement les opérations qui sont spécifiques au domaine de l'objet ou de l'agrégat sur lequel vous travaillez. Voici son article sur des référentiels génériques.

Et pour une autre vue, voir ce Ayende blog.

10voto

Fredy Treboux Points 559

Je pense qu'elles sont toutes de bonnes options (sauf peut-être 4 si vous ne voulez pas d'attacher vous-même à nhibernate), et vous semblez avoir des avantages et des inconvénients bien analysés afin de prendre une décision sur votre propre en fonction de votre entreprise. Ne vous punissez pas trop dur sur ce projet.

Je suis actuellement en train de travailler sur un mélange entre le 2 et le 3, je suppose:

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);
}

Et il y a aussi un Dépôt (T) de la classe de base.

6voto

Michael Mann Points 616

L'une des choses que nous faisons est que l'ensemble de nos référentiels ont des besoins différents, donc nous créons un ensemble d'interfaces:

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

Dans cet exemple, la lecture seule référentiel juste n'obtient à partir de la base de données. La raison de la T,V est le V représente ce qui est retourné par le référentiel et le T représente ce qui est transmis, de sorte que vous pourriez faire quelque chose comme ceci:

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

    public Customer Find(string customerName)
    {
    }
}

Je peux également créer séparer les interfaces pour l'Ajouter, mettre à Jour et de le Supprimer. De cette façon, si mon référentiel n'a pas besoin de le comportement de là, tout n'implémente pas l'interface.

1voto

anonymous Points 4000

Lors de l'utilisation de NH avec Linq votre dépôt peut être:

session.Linq<Entity>()

Les spécifications sont les choses qui concernent:

IQueryable<Entity>

Vous pouvez façade tout de suite si vous voulez, mais c'est beaucoup de travail courantes à l'abstraction, une abstraction.

Simple est bonne. Yah, NH n'bases de données, mais il offre beaucoup plus de modèles. Autres que le DAL dépendent de NH est loin d'être un péché.

1voto

trustyfrog Points 4160

Je suis un bif fan de 1 parce que je peux créer des filtres et la pagination des méthodes d'extension que je peux appliquer à la IQueryable<> les valeurs de retour de la méthode Find. Je garde les méthodes d'extension dans la couche de données, puis de construire à la volée dans la couche de gestion. (Pas totalement pur, certes.)

Bien sûr, lorsque le système se stabilise, j'ai la possibilité de présenter des méthodes de recherche en utilisant les mêmes méthodes d'extension et d'optimiser à l'aide de la touche Func<>.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X