Modèle de référentiel vs DAL

93

Sont-ils la même chose? Je viens de terminer de regarder le didacticiel Storefront de Rob Connery et ils semblent être des technologies similaires. Je veux dire, lorsque j'implémente un objet DAL, j'ai les méthodes GetStuff, Add / Delete, etc. et j'écris toujours l'interface en premier afin de pouvoir changer de db plus tard.

Suis-je déroutant les choses?

Mike
la source

Réponses:

88

Vous n'êtes certainement pas celui qui confond les choses. :-)

Je pense que la réponse à la question dépend de combien vous voulez être puriste.

Si vous voulez un point de vue DDD strict, cela vous mènera sur un chemin. Si vous considérez le référentiel comme un modèle qui nous a aidé à standardiser l'interface de la couche qui sépare les services et la base de données, cela vous en entraînera une autre.

De mon point de vue, le référentiel n'est qu'une couche d'accès aux données clairement spécifiée, ou en d'autres termes une manière standardisée d'implémenter votre couche d'accès aux données. Il existe quelques différences entre les différentes implémentations de référentiel, mais le concept est le même.

Certaines personnes mettront plus de contraintes DDD sur le référentiel tandis que d'autres utiliseront le référentiel comme médiateur pratique entre la base de données et la couche de service. Un référentiel comme un DAL isole la couche de service des spécificités d'accès aux données.

Un problème d'implémentation qui semble les rendre différents, est qu'un référentiel est souvent créé avec des méthodes qui prennent une spécification. Le référentiel renverra des données qui satisfont à cette spécification. La plupart des DAL traditionnels que j'ai vus auront un plus grand ensemble de méthodes où la méthode prendra n'importe quel nombre de paramètres. Bien que cela puisse sembler une petite différence, c'est un gros problème lorsque vous entrez dans les domaines de Linq et des Expressions. Notre interface de référentiel par défaut ressemble à ceci:

public interface IRepository : IDisposable
{
    T[] GetAll<T>();
    T[] GetAll<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter);
    T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
    void Delete<T>(T entity);
    void Add<T>(T entity);
    int SaveChanges();
    DbTransaction BeginTransaction();
}

S'agit-il d'un DAL ou d'un référentiel? Dans ce cas, je suppose que c'est les deux.

Kim

Kim Major
la source
5
En retard à la fête ici, mais pourquoi T [], pas List <T> (ou similaire)?
Mike Kingscott
27
Peut-être que IEnumerable <T> serait le meilleur.
Venemo
9
ou IQueryable <T>
kenwarner
1
Je pense que IQueryable <T> serait le meilleur choix, car il vous permet d'enchaîner les méthodes et de différer l'exécution en laissant la base de données faire tout le travail.
0lukasz0
4
@kenwarner Je pense que le retour d'IQueryable <T> laisse échapper l'abstraction. Vous devez renvoyer les objets de domaine à partir de votre référentiel.
Matthew
42

Un référentiel est un modèle qui peut être appliqué de nombreuses manières différentes, tandis que la couche d'accès aux données a une responsabilité très claire: le DAL doit savoir comment se connecter à votre stockage de données pour effectuer des opérations CRUD.

Un référentiel peut être un DAL, mais il peut également se trouver devant le DAL et servir de pont entre la couche d'objet métier et la couche de données. La mise en œuvre utilisée variera d'un projet à l'autre.

Jeromy Irvine
la source
23

Une grande différence est qu'un DAO est un moyen générique de gérer la persistance de toute entité de votre domaine. Un référentiel, en revanche, ne traite que des racines agrégées.

pondermatique
la source
26
La première chose à comprendre est qu'un référentiel en tant que modèle fait partie du système plus large connu sous le nom de Domain Driven Design. Dans le domaine DDD, les objets sont regroupés en agrégats, chacun avec une racine agrégée. Par exemple, PurchaseOrder est une racine agrégée et OrderItems sont des enfants dans la racine agrégée. Un référentiel ne traite que des racines agrégées. Autrement dit, un OrderItem par exemple n'est jamais chargé indépendamment de sa racine agrégée. Ainsi, vous n'auriez jamais de référentiel OrderItem dans DDD. Cependant, dans un système non DDD, vous pouvez avoir un OrderItemDao car Dao n'est pas limité aux racines agrégées.
pondermatic
NG, merci! J'avais commencé à voir les choses de cette façon, mais cela le rend clair. Je vais devoir commencer à lire toute la littérature DDD!
David
@bingle, excellente description des racines agrégées et de la manière dont les objets enfants sont chargés par un référentiel. Où existe-t-il un référentiel dans une application multicouche? Je pouvais le voir se trouver dans une bibliothèque de couches d'accès aux données, mais comme il charge des objets enfants, devrait-il exister dans la bibliothèque de couches logiques à la place? Mon instinct me dit la couche d'accès aux données mais je voulais votre avis sur la question.
Jeff LaFay
12

Je cherchais une réponse à une question similaire et je suis d'accord avec les deux réponses les mieux classées. En essayant de clarifier cela pour moi-même, j'ai constaté que si les spécifications, qui vont de pair avec le modèle de référentiel, sont implémentées en tant que membres de première classe du modèle de domaine, alors je peux

  • réutiliser les définitions de spécification avec différents paramètres,
  • manipuler les paramètres des instances de Spécification existantes (par exemple pour se spécialiser),
  • combinez- les,
  • exécuter une logique métier sur eux sans jamais avoir à accéder à la base de données,
  • et, bien sûr, les tester unitaire indépendamment des implémentations réelles du référentiel.

Je peux même aller aussi loin et dire qu'à moins que le modèle de référentiel ne soit utilisé avec le modèle de spécification, ce n'est pas vraiment un «référentiel», mais un DAL. Un exemple artificiel en pseudo-code:

specification100 = new AccountHasMoreOrdersThan(100)
specification200 = new AccountHasMoreOrdersThan(200)

assert that specification200.isSpecialCaseOf(specification100)

specificationAge = new AccountIsOlderThan('2000-01-01')

combinedSpec = new CompositeSpecification(
    SpecificationOperator.And, specification200, specificationAge)

for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
    assert that account.Created < '2000-01-01'
    assert that account.Orders.Count > 200

Voir l'essai de spécification de Fowler pour plus de détails (c'est ce sur quoi je me suis basé).

Un DAL aurait des méthodes spécialisées comme

IoCManager.InstanceFor<IAccountDAO>()
    .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')

Vous pouvez voir comment cela peut rapidement devenir fastidieux, d'autant plus que vous devez définir chacune des interfaces DAL / DAO avec cette approche et implémenter la méthode de requête DAL.

Dans .NET, les requêtes LINQ peuvent être un moyen d'implémenter des spécifications, mais la combinaison de spécifications (expressions) peut ne pas être aussi fluide qu'avec une solution locale. Quelques idées pour cela sont décrites dans cette question SO .

Thomas Jung
la source
2

Mon opinion personnelle est qu'il s'agit de cartographie, voir: http://www.martinfowler.com/eaaCatalog/repository.html . Ainsi, la sortie / l'entrée du référentiel sont des objets de domaine, qui sur la DAL peuvent être n'importe quoi. Pour moi, c'est un ajout / une restriction important, car vous pouvez ajouter une implémentation de référentiel pour une base de données / service / quoi que ce soit avec une mise en page différente, et vous avez un endroit clair pour vous concentrer sur le mappage. Si vous ne deviez pas utiliser cette restriction et avoir le mappage ailleurs, le fait d'avoir différentes façons de représenter les données peut avoir un impact sur le code à des endroits où il ne devrait pas changer.

Eglasius
la source
1

Tout est question d'interprétation et de contexte. Ils peuvent être très similaires voire très différents, mais tant que la solution fait le travail, qu'est-ce qu'il y a dans un nom!

c00ke
la source
1

Le référentiel est un modèle, c'est un moyen d'implémenter les choses de manière standardisée pour réutiliser le code comme nous le pouvons.

Xulfee
la source
1

L'avantage de l'utilisation du modèle de référentiel est de simuler votre couche d'accès aux données, afin que vous puissiez tester votre code de couche métier sans appeler de code DAL. Il y a d'autres avantages importants, mais cela me semble essentiel.

Shailesh
la source
1
Vous pouvez toujours vous moquer d'un DAL, il n'est pas nécessaire qu'il s'agisse d'un référentiel en soi. Le point important est que quelle que soit la stratégie d'accès aux données que vous utilisez, elle doit implémenter une interface. Cela vous permettra d'utiliser des conteneurs IoC et de tester proprement votre code métier sans avoir besoin d'un magasin de données.
cdaq
0

D'après ce que je comprends, ils peuvent signifier fondamentalement la même chose - mais la dénomination varie en fonction du contexte.

Par exemple, vous pouvez avoir une classe Dal / Dao qui implémente une interface IRepository.

Dal / Dao est un terme de couche de données; les niveaux supérieurs de votre application pensent en termes de référentiels.

télécommande
la source
0

Donc, dans la plupart des cas (simples), DAO est une implémentation de Repository?

Autant que je sache, il semble que DAO traite précisément de l'accès à la base de données (CRUD - No selects cependant?!) Tandis que Repository vous permet d'abstraire l'ensemble de l'accès aux données, peut-être une façade pour plusieurs DAO (peut-être différentes sources de données).

Suis-je sur la bonne voie?

Mike
la source
En fait, j'inverse cela et je dirais que d'un point de vue simpliste, un référentiel est un style d'implémentation particulier pour un DAO, mais oui, vous êtes sur la bonne voie. (R de CRUD = Lire, c'est donc votre choix.)
Jeromy Irvine
0

Dans le monde externe (c'est-à-dire le code client), le référentiel est le même que DAL, sauf:

(1) ses méthodes d'insertion / mise à jour / suppression sont limitées pour avoir l'objet conteneur de données comme paramètre.

(2) pour l'opération de lecture, il peut prendre une spécification simple comme un DAL (par exemple GetByPK) ou une spécification avancée.

En interne, il fonctionne avec un Data Mapper Layer (par exemple, le contexte du cadre d'entité, etc.) pour effectuer l'opération CRUD réelle.

Ce que le modèle de référentiel ne signifie pas: -

De plus, j'ai souvent vu des gens confondus pour avoir une méthode Save distincte comme exemple d'implémentation de modèle de référentiel en plus des méthodes Insert / Update / Delete qui valide toutes les modifications en mémoire effectuées par les méthodes d'insertion / mise à jour / suppression dans la base de données. Nous pouvons définitivement avoir une méthode Save dans un référentiel, mais ce n'est pas la responsabilité du référentiel d'isoler les méthodes CUD (Create, Update, Delete) et de persistance en mémoire (qui effectue l'opération réelle d'écriture / modification dans la base de données), mais le responsabilité du modèle de l'unité de travail.

J'espère que cela t'aides!

Ashraf Alam
la source
0

On pourrait soutenir qu'un «référentiel» est une classe spécifique et qu'un «DAL» est la couche entière constituée des référentiels, des DTO, des classes d'utilitaires et de tout ce qui est nécessaire.

Jonathan Allen
la source