¿Cómo debemos crear nuevas raíces agregadas en la arquitectura cqrs? En este ejemplo, quiero crear una nueva raíz agregada AR2 que tenga referencia a la primera AR1.
Estoy creando AR2 usando el método AR1 como punto de partida. Hasta ahora veo pocas opciones:
- Dentro método en AR1
createAr2RootOpt1
que podría llamarnew AR2()
y guardar este objeto db imediatelly utilizando el servicio de dominio que tenga acceso al repositorio. Podría emitir evento en la primera raíz agregada, por ejemplo.
SholdCreateAR2Event
y luego tienen una saga sin estado que reacciona ante esto y emite un comandoCreateAR2Command
que luego se maneja y realmente crea AR2 y emiteAR2CreatedEvent
. En caso de utilizar el abastecimiento de eventosSholdCreateAR2Event
, no se conservaría en el almacén de eventos, ya que no afecta el estado de la primera raíz agregada. (¿O deberíamos guardar esto en la tienda de eventos?)class AR1{ Integer id; DomainService ds; //OPTION 1 void createAr2RootOpt1(){ AR2 ar2 = new AR2(); ds.saveToRepo(ar2); } //OPTION 2 void createAr2RootOpt2(){ publishEvent(new SholdCreateAR2Event()); //we don't need this event. Shoud it still be preserved in event store? } } class AR2{ Integer id; Integer ar1Id; void handle(CreateAR2Command command){ //init this AR with values and save publishEvent(AR2CreatedEvent()); //used for projections afterwards and saved inside AR2 event store } } class Saga{ void handle(SholdCreateAR2Event ev){ emitCommand(new CreateAR2Command()); } }
¿Cuál es la forma más adecuada de hacer esto?
fuente
AR1WasCreated
? Debe serAR2WasCreated
? Además, si uso su lógica, ¿emito un eventoAR2WasCreated
antes de que se cree realmente? Y guardar este evento dentro del registro de eventos de AR1 parece problemático, ya que en realidad no necesito estos datos dentro de AR1 (no modifica nada dentro de AR1).AR1WasCreated
-> SAGA (tiene una regla si se creó A1 y luego crea A2) ->CreateAR2Command
->AR2WasCreated
.Los patrones de creación son raros .
Udi Dahan tiene algunas cosas útiles que decir sobre el problema general: no crear raíces agregadas . El punto básico es que el agregado no solo aparece de la nada, y que hay un lenguaje de dominio que describe cómo aparecen, que debe capturarse en su modelo de dominio.
Donde tiende a torcerse es que la entidad en su modelo de dominio que está procesando el comando no es la entidad que está siendo modificada por la transacción. Eso no está mal; es extraño (en comparación con los casos en que le pide a una entidad que se modifique a sí misma).
Su segundo enfoque también está bien. Los "eventos que generamos sin guardar realmente en la base de datos" a veces se denominan "eventos de dominio"
La idea básica es que, dentro de la misma transacción, el controlador de comandos genera el evento, que viaja a lo largo del bus hasta un controlador de eventos que permite que se cree el segundo agregado. Obtendrá una cohesión de código algo mejor, tal vez.
Nota: en los sistemas con fuente de eventos, generalmente no se usan eventos de esta manera.
Nota: los nombres de los eventos suelen estar en tiempo pasado: ShouldCrateAR2 tiene una ortografía incorrecta.
Sí, si solo está lanzando un evento en el bus síncrono para ejecutar código remoto, entonces no debería guardar ese evento en el libro de registro. Es solo un detalle de implementación a esta escala.
Evite modificar dos secuencias de eventos diferentes en la misma transacción. Si esta creación también representa un cambio en AR1, entonces la respuesta habitual sería modificar AR1 en esta transacción, con un suscriptor asíncrono a esos eventos que es responsable de disparar el comando para crear AR2.
El manejo de comandos idempotentes ayuda mucho aquí.
fuente
AR1.doSmthn(AR2 param)
ya que cualquier proyección de lectura que creo no tiene datos completos que necesito (solo AR2 tiene datos completos).