Estoy comenzando con DDD y entiendo que las raíces agregadas se utilizan para garantizar la coherencia transnacional. No debemos modificar múltiples agregados en un servicio de aplicación.
Sin embargo, me gustaría saber cómo lidiar con la siguiente situación.
Tengo una raíz agregada llamada Productos.
También hay una raíz agregada llamada Grupo.
Ambos tienen Id, y se pueden editar de forma independiente.
Varios productos pueden apuntar al mismo grupo.
Tengo un servicio de aplicación que puede cambiar el grupo de un producto:
ProductService.ChangeProductGroup(string productId, string groupId)
- Comprobar grupo existe
- Obtener producto del repositorio
- Establecer su grupo
- Escriba el producto nuevamente en el repositorio
También tengo un servicio de aplicación donde se puede eliminar el grupo:
GroupService.DeleteGroup(string groupId)
1. Obtenga productos del repositorio cuyo groupId esté configurado en groupId proporcionado, asegúrese de que el recuento sea 0 o cancele 2. Elimine el grupo del repositorio de grupos 3. Guarde los cambios
Mi pregunta es el siguiente escenario, ¿qué pasaría si:
En ProductService.ChangeProductGroup, verificamos que el grupo existe (sí existe), luego, justo después de esta verificación, un usuario separado elimina el productGroup (a través del otro GroupService.DeleteGroup). En este caso, establecemos una referencia a un producto que acaba de eliminarse.
¿Es esta una falla en mi diseño que debería usar un diseño de dominio diferente (agregando elementos adicionales si es necesario), o tendría que usar transacciones?
fuente
¿Por qué no almacena los identificadores de producto en la entidad del Grupo? De esta manera, solo se trata de un único agregado que facilitará las cosas.
Luego deberá implementar algún tipo de patrón de concurrencia, por ejemplo, si elige concurrencia optimista, simplemente agregue una propiedad de versión a la entidad del Grupo y arroje una excepción si las versiones no coinciden al actualizar, es decir
Agregar producto a un grupo
Muchos ORM tienen una simultaneidad optimista incorporada usando identificadores de versión o marcas de tiempo, pero es fácil de usar. Aquí hay una buena publicación sobre cómo se hace en Nhibernate http://ayende.com/blog/3946/nhibernate-mapping-concurrency .
fuente
Aunque las transacciones pueden ayudar, hay otra forma, especialmente si su escenario se limita a unos pocos casos.
Podría incluir comprobaciones en las consultas que realizan las mutaciones, haciendo que cada par de comprobación y mutación sea una operación atómica.
La consulta de actualización del producto interna se une al grupo (recién referenciado). Esto hace que no actualice nada si ese grupo se ha ido.
La consulta de eliminación de grupo une todos los productos que apuntan a ella y tiene la condición adicional de que (cualquier columna de) el resultado de la unión debe ser nulo. Esto hace que no elimine nada si algún producto lo señala.
Las consultas devuelven el número de filas que coincidieron o se actualizaron. Si el resultado es 0, entonces perdió una condición de carrera y no hizo nada. Puede lanzar una excepción, y la capa de aplicación puede manejar eso como quiera, como al intentar nuevamente desde el principio.
fuente