Errores del diseño impulsado por dominio con Entity Framework

12

Una gran cantidad de tutoriales sobre DDD que estudié cubren principalmente la teoría. Todos tienen ejemplos de código rudimentario (Pluralsight y similares).

En la web también hay intentos de algunas personas de crear tutoriales que cubran DDD con EF. Si comienza a estudiarlos brevemente, notará rápidamente que difieren mucho entre sí. Algunas personas recomiendan mantener la aplicación mínima y evitar la introducción de capas adicionales, por ejemplo, el repositorio encima de EF , otras están decididamente generando capas adicionales, a menudo incluso violando SRP al inyectar DbContexten Raíces Agregadas.

Me disculpo terriblemente si hago una pregunta basada en una opinión, pero ...

Cuando se trata de practicar, Entity Framework es uno de los ORM más potentes y ampliamente utilizados. Lamentablemente, no encontrará un curso completo que abarque DDD.


Aspectos importantes:

  • Entity Framework trae UoW & Repository ( DbSet) fuera de la caja

  • con EF sus modelos tienen propiedades de navegación

  • con EF todos los modelos son siempre disponible fuera DbContext(que se representan como una DbSet)

Trampas:

  • no puede garantizar que sus modelos secundarios solo se vean afectados por la raíz agregada: sus modelos tienen propiedades de navegación y es posible modificarlos y llamardbContext.SaveChanges()

  • con la DbContextque se puede acceder a cada modelo, por tanto, eludir agregado Raíz

  • puede restringir el acceso a los elementos secundarios del objeto de la raíz a través ModelBuilderde OnModelCreatingmétodo marcándolos como campos - Todavía no creer que es la forma correcta de hacer las DDD y además es difícil de evaluar qué tipo de aventuras que esto puede conducir en el futuro ( bastante escépticos )

Conflictos:

  • sin implementar otra capa de repositorio que devuelva Agregado, ni siquiera podemos resolver en parte las trampas mencionadas anteriormente

  • Al implementar una capa adicional de repositorio, estamos ignorando las características integradas de EF (todo DbSetya es un repositorio) y complicando demasiado la aplicación


Mi conclusión:

Perdone mi ignorancia, pero en base a la información anterior, o bien Entity Framework no es adecuado para el diseño dirigido por dominio o el diseño dirigido por dominio es un enfoque imperfecto y obsoleto .

Sospecho que cada uno de los enfoques tiene sus méritos, pero ahora estoy completamente perdido y no tengo la menor idea de cómo conciliar EF con DDD.


Si me equivoco, ¿podría alguien al menos detallar un conjunto simple de instrucciones (o incluso proporcionar ejemplos de código decente) de cómo hacer DDD con EF, por favor?

Alex Herman
fuente
Detallé los pasos aquí de acuerdo con mi comprensión de cómo funciona EF. Aún así, esos pasos no manejan el problema de acceder a los niños por navegación. propiedades o por DbSets fuera de DbContext.
Alex Herman el

Respuestas:

8

DDD y EF tienen poco o nada que ver entre sí.

DDD es un concepto de modelado. Significa pensar en el Dominio, los Requisitos del Negocio y modelarlos. Especialmente en el contexto de la orientación a objetos, significa crear un diseño que refleje las funciones y capacidades comerciales.

EF es una tecnología de persistencia. Se ocupa principalmente de datos y registros de bases de datos.

Estos dos están muy divorciados. Un diseño DDD puede usar EF de alguna forma debajo del capó, pero los dos no deben interactuar de ninguna otra manera.

Algunas interpretaciones del diseño impulsado por dominios en realidad abogan por el modelado de datos, y creo que de esto se trata su pregunta. En esta interpretación, las "Entidades" y los "Objetos de valor" son esencialmente poseedores de datos sin funciones únicamente, y el diseño se refiere a qué propiedades tienen y qué relación tienen entre sí. En este contexto, puede aparecer DDD vs. EF.

Sin embargo, esta interpretación es defectuosa, y recomendaría ignorarla por completo.

En conclusión : DDD y EF no son mutuamente excluyentes, en realidad son irrelevantes entre sí, siempre que esté realizando un modelado de objetos adecuado y no un modelado de datos. Los objetos DDD no deben tener ninguna forma o artefactos EF. Las entidades DDD no deben ser EF "entidades", por ejemplo. Dentro de alguna función relevante para el negocio, un diseño DDD puede usar EF con algunos objetos de datos relacionados, pero estos siempre deben estar ocultos bajo una interfaz orientada al comportamiento relevante para el negocio.

Robert Bräutigam
fuente
1
EF es solo un ahorro de tiempo. El seguimiento de cambios y la persistencia de los agregados es donde EF ya ayuda mucho. Desafortunadamente, actualmente no hay forma de definir la forma de los agregados a nivel de configuración.
Pavel Voronin
6

Trate a EF por lo que es, es decir, la biblioteca de acceso a datos que tiene un tipo ligeramente más fuerte que ADO.NET sin formato. No recomendaría modelar su dominio usando clases de entidad EF al igual que no recomendaría modelar el dominio usando DataSet o DataTable sin formato.

Entiendo que EF se está vendiendo como un acceso directo entre el acceso a la base de datos y el modelado de dominios, sin embargo, este enfoque es intrínsecamente defectuoso ya que aborda dos problemas en gran medida no relacionados. Hubo otros intentos en .NET para hacer que una clase realizara algunas cosas completamente no relacionadas (por ejemplo, Remoto de .NET) y no terminaron bien.

Haga el DDD usando clases POCO y no permita que el esquema de la base de datos controle su diseño. Mantenga EF dentro del repositorio / capa de persistencia y no permita que las entidades EF se filtren afuera.

Kola
fuente
5

Entity Framework trae UoW & Repository (DbSet) fuera de la caja

No.

Las abstracciones de Entity Framework se crearon teniendo en cuenta ORM, no DDD. La DbSetabstracción en cualquier versión de Entity Framework no se acerca a la simplicidad de un Repositorio DDD, sin mencionar DbContextque expone un millón de cosas más que UnitOfWork.

Aquí hay una lista no exhaustiva de elementos en el resumen de EF Core 2.1 DbSet<TEntity>que no necesitamos en DDD:

  • Attach(TEntity) y todos sus hermanos
  • Find(Object[])
  • Update(TEntity) y todos sus hermanos
  • Implementar IQueryable

Además de arrastrar dependencias innecesarias con ellos, estos oscurecen la intención de un Repositorio que normalmente expone un comportamiento de recopilación muy simple. Además, las abstracciones permeables son una tentación constante para que los desarrolladores se acoplen demasiado a EF y una amenaza para la Separación de preocupaciones.

En pocas palabras: debe envolver estos gorditos en conceptos agradables y simplificados y adivinar qué, eso significa introducir clases adicionales.

Un ejemplo relativamente sólido de lo que puede hacer con EF y DDD (aunque algunos puntos de vista expresados ​​son discutibles): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

otros están decididamente generando capas adicionales, a menudo incluso violando SRP al inyectar DbContext en Aggregate Roots

Realmente no veo la conexión entre las dos partes de esta oración. No importa el enfoque, hay una cosa en DDD llamada Application Service y ahí es donde manipulas la Unidad de Trabajo / Repositorio (o DbContext). No en raíces agregadas.

Si bien podría ser un enfoque válido si fuera una compensación educada, la reciente tendencia anti-repositorio, "minimalismo del marco de la entidad" es delirante. Culpa a los patrones DDD por la fricción que ocurre con Entity Framework cuando realmente son los creadores de EF los que no hicieron nada para que su marco cumpla con las mejores prácticas de fábrica. Mientras tanto, se están uniendo estrechamente a ese mismo marco con todos los problemas en términos de seguridad de código y mantenibilidad que pueden surgir.

guillaume31
fuente
2

Conflictos:

sin implementar otra capa de repositorio que devuelva Agregado, ni siquiera podemos resolver en parte las trampas mencionadas anteriormente

Al implementar una capa adicional de repositorio, ignoramos las características integradas de EF (cada DbSet ya es un repositorio) y complicamos demasiado la aplicación

He utilizado un enfoque en el que cada Agregado obtiene su propio DBContext, mapeando justo lo que se necesita para el Agregado. Creo que esto también ha sido descrito por Julie Lerman.

Esto funcionó muy bien, pero podría no ser suficiente para modelos más interesantes, donde no desea vincular sus conceptos a sus entidades.

mvg
fuente
También vi este video dddcommunity.org/ddd-contributors/…
Alex Herman
¿Hay algún beneficio del enfoque DBContext Per Aggregate? ¿Es esta la forma predeterminada de implementar DDD con EF?
Alex Herman
¿No se refería Julie Lerman a DbContext por contexto acotado?
Mvision
0

Solo me gustaría compartir una posible solución para su consideración:

  1. evite hacer referencia al proyecto EF en la capa de servicio directamente

  2. crear una capa de repositorio adicional (usa el proyecto EF y devuelve la raíz agregada)

  3. referenciar la capa de repositorio en el proyecto de capa de servicio

Arquitectura :

  • UI

  • Capa de controlador

  • Capa de servicio

  • Capa de repositorio

  • Marco de la entidad

  • Proyecto principal (contiene modelos EF)


Las trampas que veo con este enfoque:

  • Si un repositorio devuelve raíz agregada no como árbol modelo EF (por ejemplo, devolvemos un objeto mapeado), estamos perdiendo la capacidad de EF de rastrear cambios

  • si Aggregate Root es un modelo EF, todas sus propiedades de navegación aún están disponibles , aunque no podamos tratarlas DbContext(no hacemos referencia al proyecto EF en la capa de servicio)

Alex Herman
fuente