Pièges de la conception pilotée par domaine avec Entity Framework


12

Beaucoup de tutoriels sur DDD que j'ai étudiés couvrent principalement la théorie. Ils ont tous des exemples de code rudimentaires (Pluralsight et similaires).

Sur le Web, quelques personnes tentent également de créer des didacticiels couvrant DDD avec EF. Si vous commencez à les étudier brièvement - vous remarquez rapidement qu'ils diffèrent beaucoup les uns des autres. Certaines personnes recommandent de garder l'application minimale et d'éviter d'introduire des couches supplémentaires, par exemple un référentiel au-dessus d'EF , d'autres génèrent décidément des couches supplémentaires, souvent même en violant SRP en injectant DbContextdans les racines d'agrégat.

Je m'excuse terriblement si je pose une question d'opinion, mais ...

En matière de pratique, Entity Framework est l'un des ORM les plus puissants et les plus utilisés. Malheureusement, vous ne trouverez pas de cours complet couvrant DDD.


Aspects importants:

  • Entity Framework sort UoW & Repository ( DbSet) de la boîte

  • avec EF vos modèles ont des propriétés de navigation

  • avec EF tous les modèles sont toujours disponibles off DbContext(ils sont représentés comme un DbSet)

Pièges:

  • vous ne pouvez pas garantir que vos modèles enfants sont uniquement affectés via la racine agrégée - vos modèles ont des propriétés de navigation et il est possible de les modifier et d'appelerdbContext.SaveChanges()

  • avec DbContextvous pouvez accéder à chacun de vos modèles, contournant ainsi la racine agrégée

  • vous pouvez restreindre l'accès aux enfants de l'objet racine via la méthode ModelBuilderin en les marquant comme des champs - je ne pense toujours pas que ce soit la bonne façon de faire à propos de DDD et il est difficile d'évaluer le type d'aventures que cela pourrait conduire à l'avenir ( assez sceptique) )OnModelCreating

Conflits:

  • sans implémenter une autre couche de référentiel qui renvoie Aggregate, nous ne pouvons même pas résoudre en partie les pièges susmentionnés

  • en implémentant une couche supplémentaire de référentiel, nous ignorons les fonctionnalités intégrées d'EF (tout DbSetest déjà un dépôt) et compliquons trop l'application


Ma conclusion:

Veuillez excuser mon ignorance, mais sur la base des informations ci-dessus - c'est soit Entity Framework n'est pas adéquat pour la conception pilotée par domaine ou la conception pilotée par domaine est une approche imparfaite et obsolète .

Je soupçonne que chacune des approches a ses mérites, mais je suis complètement perdu maintenant et je n'ai pas la moindre idée de la façon de réconcilier EF avec DDD.


Si je me trompe - quelqu'un pourrait-il au moins détailler un simple ensemble d'instructions (ou même fournir des exemples de code décents) sur la façon de traiter DDD avec EF, s'il vous plaît?


J'ai détaillé les étapes ici en fonction de ma compréhension du fonctionnement d'EF. Pourtant, ces étapes ne gèrent pas un problème d'accès aux enfants par nav. propriétés ou par DbSets off DbContext.
Alex Herman

Réponses:


8

DDD et EF n'ont presque rien à voir l'un avec l'autre.

DDD est un concept de modélisation. Cela signifie penser au domaine, aux exigences commerciales et les modéliser. Surtout dans le contexte de l'orientation objet, cela signifie créer un design qui reflète les fonctions et capacités de l'entreprise.

EF est une technologie de persistance. Il concerne principalement les données et les enregistrements de bases de données.

Ces deux sont fortement divorcés. Une conception DDD peut utiliser EF sous une forme quelconque sous le capot, mais les deux ne doivent pas interagir d'une autre manière.

Certaines interprétations de la conception pilotée par domaine préconisent en fait la modélisation des données, et je pense que c'est de cela qu'il s'agit. Dans cette interprétation, les «entités» et les «objets de valeur» sont essentiellement des détenteurs de données sans fonction uniquement, et la conception se préoccupe des propriétés qu'elles détiennent et de la relation qu'elles ont entre elles. Dans ce contexte, DDD vs. EF peuvent apparaître.

Cette interprétation est cependant imparfaite, et je recommanderais fortement de l'ignorer complètement.

En conclusion : DDD et EF ne s'excluent pas mutuellement, ils ne sont en fait pas pertinents l'un pour l'autre, tant que vous effectuez une modélisation d'objet appropriée et non une modélisation de données. Les objets DDD ne doivent en aucun cas être des artefacts EF. Les entités DDD ne doivent pas être des "entités" EF par exemple. Dans une fonction pertinente pour l'entreprise, une conception DDD peut utiliser EF avec certains objets de données associés, mais ceux-ci doivent toujours être masqués sous une interface orientée comportementale pertinente pour l'entreprise.


1
EF n'est qu'un gain de temps. Le suivi des modifications et la persistance des agrégats sont les domaines où EF aide déjà beaucoup. Malheureusement, il n'existe actuellement aucun moyen de définir la forme des agrégats au niveau de la configuration.
Pavel Voronin

6

Traitez EF pour ce qu'il est, c'est-à-dire une bibliothèque d'accès aux données qui n'est que légèrement plus fortement typée que ADO.NET brut. Je ne recommanderais pas de modéliser votre domaine à l'aide de classes d'entités EF, tout comme je ne recommanderais pas de modéliser un domaine à l'aide de DataSet ou DataTable bruts.

Je comprends que EF est vendu comme un raccourci entre l'accès à la base de données et la modélisation de domaine, mais cette approche est intrinsèquement défectueuse car elle résout deux problèmes largement indépendants. Il y a eu d'autres tentatives dans .NET pour faire exécuter à une classe des choses complètement indépendantes (par exemple .NET Remoting) et elles n'ont pas bien fini.

Faites le DDD à l'aide des classes POCO et ne laissez pas le schéma de base de données piloter votre conception. Gardez EF à l'intérieur du référentiel / couche de persistance et ne laissez pas les entités EF s'échapper à l'extérieur.


5

Entity Framework sort UoW & Repository (DbSet) de la boîte

Non.

Les abstractions Entity Framework ont ​​été construites avec ORM, pas DDD, à l'esprit. L' DbSetabstraction dans n'importe quelle version d'Entity Framework est loin d'être la simplicité d'un référentiel DDD - sans parler de DbContextce qui expose un million de choses plus qu'un UnitOfWork.

Voici une liste non exhaustive des éléments du résumé d'EF Core 2.1 DbSet<TEntity>dont nous n'avons pas besoin dans DDD:

  • Attach(TEntity) et tous ses frères et sœurs
  • Find(Object[])
  • Update(TEntity) et tous ses frères et sœurs
  • Exécution IQueryable

En plus de traîner avec eux des dépendances inutiles, celles-ci obscurcissent l'intention d'un référentiel qui expose normalement un comportement de collecte très simple. De plus, les abstractions qui fuient sont une tentation constante pour les développeurs de trop se coupler à EF et une menace pour la séparation des préoccupations.

Bottom line: vous devez envelopper ces fatties dans de beaux concepts rationalisés et deviner quoi, cela signifie introduire des classes supplémentaires.

Un exemple relativement solide de ce que vous pouvez faire avec EF et DDD (bien que certains points de vue exprimés soient discutables): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

d'autres génèrent décidément des couches supplémentaires, violant même souvent SRP en injectant DbContext dans les racines d'agrégat

Je ne vois vraiment pas le lien entre les deux parties de cette phrase. Quelle que soit l'approche, il existe une chose dans DDD appelée Application Service et c'est là que vous manipulez l'unité de travail / référentiel (ou DbContext). Pas dans les racines agrégées.

Bien qu'il puisse s'agir d'une approche valable s'il s'agissait d'un compromis éclairé, la récente tendance anti-référentiel «minimalisme Entity Framework» est délirante. Il blâme les modèles DDD pour la friction qui se produit avec Entity Framework alors que ce sont vraiment les créateurs EF qui n'ont rien fait pour rendre leur framework conforme aux meilleures pratiques. Pendant ce temps, ils sont étroitement liés à ce cadre même avec tous les problèmes de sécurité et de maintenabilité du code qui peuvent en découler.


2

Conflits:

sans implémenter une autre couche de référentiel qui renvoie Aggregate, nous ne pouvons même pas> résoudre en partie les pièges susmentionnés

en implémentant une couche supplémentaire de référentiel, nous ignorons les fonctionnalités intégrées d'EF (chaque DbSet est déjà un dépôt) et compliquons trop l'application

J'ai utilisé une approche où chaque agrégat obtient son propre DBContext, mappant exactement ce qui est nécessaire pour l'agrégat. Je pense que cela a également été décrit par Julie Lerman.

Cela a très bien fonctionné, mais pourrait ne pas suffire pour des modèles plus intéressants, où vous ne voulez pas lier vos concepts à vos entités.



Y a-t-il des avantages de l'approche DBContext Per Aggregate? Est-ce la façon par défaut d'implémenter DDD avec EF?
Alex Herman

Julie Lerman ne voulait-elle pas dire DbContext per Bounded context?
Mvision

0

Je voudrais juste partager une solution possible pour examen:

  1. éviter de référencer directement le projet EF dans Service Layer

  2. créer une couche de référentiel supplémentaire (utilise le projet EF et renvoie la racine agrégée)

  3. référencer le projet Repository Layer in Service Layer

Architecture :

  • UI

  • Couche de contrôleur

  • Couche de service

  • Couche de référentiel

  • Cadre d'entité

  • Projet principal (contient des modèles EF)


Les pièges que je vois avec cette approche:

  • si un référentiel renvoie la racine agrégée non pas comme arbre de modèle EF (par exemple, nous renvoyons un objet mappé) - nous perdons la capacité d'EF à suivre les modifications

  • si la racine agrégée est un modèle EF - toutes ses propriétés de navigation sont toujours disponibles , même si nous ne pouvons pas les traiter DbContext(nous ne référençons pas le projet EF dans la couche de service)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.