visual studio relaciones partir hacer generar entre diagramas diagrama crear como community codigo clases c# .net architecture orm domain-driven-design

c# - relaciones - generar diagrama de clases visual studio 2017



Modelo de dominio rico con comportamientos y ORM (4)

Al hacer DDD por primera vez, ignora las preocupaciones de persistencia. El ORM está acoplado a un RDBMS, por lo que es una preocupación persistente.

Un ORM modela la estructura de persistencia NO el dominio. Básicamente, el repositorio debe "convertir" la raíz agregada recibida en una o varias entidades de persistencia. El Contexto delimitado es muy importante ya que la raíz agregada cambia de acuerdo con lo que también intentas lograr.

Supongamos que desea guardar el miembro en el contexto de una nueva oferta asignada. Entonces tendrás algo como esto (por supuesto, este es solo un escenario posible)

public interface IAssignOffer { int OwnerId {get;} Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc); IEnumerable<Offer> NewOffers {get; } } public class Member:IAssignOffer { /* implementation */ } public interface IDomainRepository { void Save(IAssignOffer member); }

A continuación, el repositorio solo obtendrá los datos necesarios para cambiar las entidades NH y eso es todo.

Acerca de EVent Sourcing, creo que hay que ver si se ajusta a su dominio y no veo ningún problema con el uso de Event Sourcing solo para almacenar las raíces agregadas del dominio mientras que el resto (principalmente infraestructura) se puede almacenar de manera normal (relacional mesas). Creo que CQRS te da una gran flexibilidad en este asunto.

Después de ver la presentación de NDC12 "Crafting Wicked Domain Models" de Jimmy Bogard ( http://ndcoslo.oktaset.com/Agenda ), estaba vagando sobre cómo persistir ese tipo de modelo de dominio.
Esta es una clase de muestra de la presentación:

public class Member { List<Offer> _offers; public Member(string firstName, string lastName) { FirstName = firstName; LastName = lastName; _offers = new List<Offer>(); } public string FirstName { get; set; } public string LastName { get; set; } public IEnumerable<Offer> AssignedOffers { get { return _offers; } } public int NumberOfOffers { get; private set; } public Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc) { var value = valueCalc.CalculateValue(this, offerType); var expiration = offerType.CalculateExpiration(); var offer = new Offer(this, offerType, expiration, value); _offers.Add(offer); NumberOfOffers++; return offer; } }

Así que hay algunas reglas contenidas en este modelo de dominio:
- El miembro debe tener nombre y apellido
- Número de ofertas no pueden ser cambiadas fuera
- El miembro es responsable de crear una nueva oferta, calcular su valor y asignación

Si trata de asignarlo a algún ORM como Entity Framework o NHibernate, no funcionará. Entonces, ¿cuál es el mejor enfoque para asignar este tipo de modelo a la base de datos con ORM?
Por ejemplo, ¿cómo puedo cargar AssignedOffers desde DB si no hay un configurador?

Lo único que tiene sentido para mí es usar la arquitectura de comando / consulta: las consultas siempre se realizan con DTO como resultado, no las entidades de dominio, y los comandos se realizan en modelos de dominio. Además, la fuente de eventos es perfecta para los comportamientos en el modelo de dominio. Pero este tipo de arquitectura CQS tal vez no sea adecuada para todos los proyectos, especialmente Brownfield. ¿O no?

Soy consciente de preguntas similares aquí, pero no pude encontrar un ejemplo concreto y una solución.


Esta es en realidad una muy buena pregunta y algo que he contemplado. Es potencialmente difícil crear objetos de dominio adecuados que estén completamente encapsulados (es decir, sin establecedores de propiedades) y usar un ORM para construir los objetos de dominio directamente.

En mi experiencia hay 3 formas de resolver este problema:

  • Como ya lo mencionó Luka, NHibernate admite la asignación a campos privados, en lugar de establecedores de propiedades.
  • Si usa EF (que no creo que sea compatible con lo anterior), podría usar el patrón de recuerdo para restaurar el estado de sus objetos de dominio. por ejemplo, utiliza el marco de entidad para rellenar los objetos ''de recuerdo'' que sus entidades de dominio aceptan para establecer sus campos privados.
  • Como ha señalado, el uso de CQRS con la fuente de eventos elimina este problema. Este es mi método preferido para crear objetos de dominio perfectamente encapsulados, que también tienen todos los beneficios añadidos de la fuente de eventos.

Hilo viejo. Pero hay una publicación más reciente (a finales de 2014) por Vaughn Vernon que aborda solo este escenario, con referencia particular al Entity Framework. Dado que de alguna manera me costó encontrar esa información, tal vez pueda ser útil publicarla aquí también.

Básicamente, la publicación aboga por el objeto de dominio del Product (agregado) para envolver el objeto de datos ProductState EF POCO en lo que concierne al lado de la "bolsa de datos" de las cosas. Por supuesto, el objeto de dominio aún agregaría todo su rico comportamiento de dominio a través de métodos / accesores específicos del dominio, pero recurriría al objeto de datos interno cuando tiene que obtener / establecer sus propiedades.

Copiando fragmento directamente desde la publicación:

public class Product { public Product( TenantId tenantId, ProductId productId, ProductOwnerId productOwnerId, string name, string description) { State = new ProductState(); State.ProductKey = tenantId.Id + ":" + productId.Id; State.ProductOwnerId = productOwnerId; State.Name = name; State.Description = description; State.BacklogItems = new List<ProductBacklogItem>(); } internal Product(ProductState state) { State = state; } //... private readonly ProductState State; } public class ProductState { [Key] public string ProductKey { get; set; } public ProductOwnerId ProductOwnerId { get; set; } public string Name { get; set; } public string Description { get; set; } public List<ProductBacklogItemState> BacklogItems { get; set; } ... }

El repositorio usaría el constructor interno para instanciar (cargar) una instancia de entidad desde su versión persistente de base de datos.

Lo único que puedo agregar a mí mismo es que, probablemente, el objeto de dominio del Product debe ensuciarse con un acceso más solo con el fin de la persistencia a través de EF: en el mismo lugar en que el new Product(productState) permite que una entidad de dominio se cargue desde la base de datos Se debe permitir el camino opuesto a través de algo como:

public class Product { // ... internal ProductState State { get { // return this.State as is, if you trust the caller (repository), // or deep clone it and return it } } } // inside repository.Add(Product product): dbContext.Add(product.State);


Para AssignedOffers: si observa el código, verá que AssignedOffers devuelve el valor de un campo. NHibernate puede rellenar ese campo así: Mapa (x => x.AssignedOffers) .Access.Field ().

De acuerdo con el uso de CQS.