entity framework - started - Preocupaciones de diseño de EF 4.2 Code First y DDD
example entity framework c# (2)
Tengo varias preocupaciones cuando trato de hacer el desarrollo DDD con el código EF 4.2 (o EF 4.1) primero. He hecho una investigación exhaustiva pero no he encontrado respuestas concretas para mis preocupaciones específicas. Aquí están mis preocupaciones:
El dominio no puede conocer la capa de persistencia, o en otras palabras, el dominio está completamente separado de EF. Sin embargo, para conservar los datos en la base de datos, cada entidad debe adjuntarse o agregarse al contexto EF. Sé que se supone que debes usar fábricas para crear instancias de las raíces agregadas, de modo que la fábrica podría potencialmente registrar la entidad creada con el contexto EF. Esto parece violar las reglas de DDD ya que la fábrica es parte del dominio y no parte de la capa de persistencia. ¿Cómo debo crear y registrar entidades para que persistan correctamente en la base de datos cuando sea necesario?
¿Debería ser una entidad agregada la que creara sus entidades secundarias? Lo que quiero decir es que, si tengo una
Organization
y esaOrganization
tiene una colección de entidades deEmployee
, ¿debería laOrganization
tener un método comoCreateEmployee
oAddEmployee
? Si no es así, ¿cómo se crea una entidad deEmployee
teniendo en cuenta que la raíz agregada de laOrganization
''posee'' cada entidad deEmployee
?Cuando se trabaja con código EF primero, los ID (en forma de columnas de identidad en la base de datos) de cada entidad se manejan automáticamente y, en general, nunca se deben cambiar por código de usuario. Dado que DDD declara que el dominio está separado de la ignorancia de persistencia, parece que exponer los ID es algo extraño de hacer en el dominio, porque esto implica que el dominio debería manejar la asignación de ID únicos a las entidades recién creadas. ¿Debería preocuparme por exponer las propiedades de identificación de las entidades?
Me doy cuenta de que estas son preguntas de diseño de final abierto, pero estoy tratando de hacer mi mejor esfuerzo para cumplir con los patrones de diseño de DDD mientras uso EF como mi capa de persistencia.
¡Gracias por adelantado!
El principal problema con la compatibilidad EF-DDD parece ser cómo persistir las propiedades privadas. La solución propuesta por Yves parece ser una solución para la falta de poder de EF en algunos casos. Por ejemplo, realmente no se puede hacer DDD con la API Fluent, que requiere que las propiedades de estado sean públicas. He encontrado que solo el mapeo con archivos .edmx te permite dejar las Entidades del dominio en estado puro. No lo obliga a hacer cosas públicas o agregar ningún atributo dependiente de EF.
Las entidades siempre deben ser creadas por alguna raíz agregada. Vea una gran publicación de Udi Dahan: http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/ Siempre cargando algunos agregados y creando entidades a partir de allí también resuelve un problema de adjuntar una entidad a Contexto EF. No necesita adjuntar nada manualmente en ese caso. Se adjuntará automáticamente porque el agregado cargado desde el repositorio ya está adjunto y tiene una referencia a una nueva entidad. Mientras que la interfaz del repositorio pertenece al dominio, la implementación del repositorio pertenece a la infraestructura y conoce EF, contextos, conexiones, etc.
Tiendo a tratar ID autogenerados como un detalle de implementación del almacén persistente, que debe ser considerado por la entidad de dominio pero no debe exponerse. Así que tengo una propiedad de ID privada que se asigna a la columna autogenerada y otra a la ID pública que es significativa para el dominio, como la ID de la tarjeta de identidad o el número de pasaporte para una clase de persona. Si no hay datos tan significativos, entonces uso el tipo Guid, que tiene una gran característica de crear (casi) identificadores únicos sin necesidad de llamadas a la base de datos. Entonces, en este patrón, uso esos Guid / MeaningfulID para cargar agregados desde un repositorio mientras que los ID autogenerados son usados internamente por la base de datos para hacer uniones más rápidas (Guid no es bueno para eso).
En 1: no estoy muy familiarizado con EF, pero usando el enfoque de mapeo basado en código / convención, supongo que no es demasiado difícil mapear POCOs con getters y setters (incluso manteniendo esa DbContext
" DbContext
with DbSet
properties" en otro proyecto no debería ser tan difícil). No consideraría las POCO como la Raíz agregada. Más bien representan "el estado dentro de un agregado que desea persistir". Un ejemplo a continuación:
// This is what gets persisted
public class TrainStationState {
public Guid Id { get; set; }
public string FullName { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
// ... more state here
}
// This is what you work with
public class TrainStation : IExpose<TrainStationState> {
TrainStationState _state;
public TrainStation(TrainStationState state) {
_state = state;
//You can also copy into member variables
//the state that''s required to make this
//object work (think memento pattern).
//Alternatively you could have a parameter-less
//constructor and an explicit method
//to restore/install state.
}
TrainStationState IExpose.GetState() {
return _state;
//Again, nothing stopping you from
//assembling this "state object"
//manually.
}
public void IncludeInRoute(TrainRoute route) {
route.AddStation(_state.Id, _state.Latitude, _state.Longitude);
}
}
Ahora, con respecto al ciclo de vida agregado, hay dos escenarios principales:
- Crear un nuevo agregado: puede usar una fábrica, un método de fábrica, un constructor, un constructor, ... lo que se ajuste a sus necesidades. Cuando necesite persistir el agregado, consulte su estado y persista (normalmente este código no reside dentro de su dominio y es bastante genérico).
- Recuperando un agregado existente: puede usar un repositorio, un dao, ... lo que se ajuste a sus necesidades. Es importante comprender que lo que está recuperando del almacenamiento persistente es un POCO de estado, que debe inyectar en un agregado prístino (o usarlo para poblar sus miembros privados). Todo esto sucede detrás de la fachada del repositorio / DAO. No confundas tus sitios de llamadas con este comportamiento genérico.
En 2: varias cosas vienen a la mente. Aquí hay una lista:
- Las raíces agregadas son límites de consistencia. ¿Qué requisitos de coherencia ves entre una organización y un empleado?
- La organización PODRÍA actuar como una fábrica de Empleado, sin mutar el estado de la Organización.
- La "propiedad" no es de lo que se tratan los agregados.
- Las raíces agregadas generalmente tienen métodos que crean entidades dentro del agregado. Esto tiene sentido porque las raíces son responsables de aplicar la coherencia dentro del agregado.
En 3: Asigne identificadores desde el exterior, sobrevíselo, continúe. Sin embargo, eso no implica exponerlos (solo en el estado POCO).