Questa è la mia attuale configurazione del caso d'uso CQRS:
-
Il DTO del comando viene ricevuto nel gestore del livello applicazione dove mappiamo il DTO del comando agli oggetti del dominio appropriati, se necessario, reidratiamo la radice aggregata dal repository e chiamiamo qualche metodo su AR
class CommandHandler{ handle(Command command){ Dom1 dom1 = new Dom1(command.d1); Dom2 dom2 = new Dom2(command.d2); AggregateRoot ar = repo.rehydrate(command.arId); ar.doSmth(dom1, dom2, command.int1); } }
-
All'interno del metodo doSmth in AR, non ho immediatamente un evento da applicare, ma devo passare alcuni argomenti all'entità che fa parte di questo AR. Quindi all'interno del metodo doSmth ho
class AggregateRoot{ void doSmth(Dom1 dom1, Dom2 dom2, Integer int1){ subEnt = new OrherSubEntity(); subEnt.doSmth(int1); } }
-
Ora ho un'entità secondaria che viene attivata e genera un DomainEvent. Questo evento di dominio deve essere parte del flusso di eventi che viene salvato in EventStore e allo stesso tempo viene propagato a qualsiasi listener in questa radice aggregata.
class SubEntity{ void doSmth(Integer int1){ //validate int1 apply(new SubEntityEvent(int1)); } void when(SubEntityEvent event){ //just modify local fields //used also in event sourcing rehydration } }
-
Poiché la seconda entità secondaria che sta ascoltando SubEntityEvent è ora attivata, esegue l'operazione intensa della CPU e genera SomeEnterprise DomainCent. Questo evento dovrebbe anche far parte del flusso di eventi che viene salvato in EventStore. Viene anche propagato ad altre sub-entità nella stessa AR ma poiché nessun altro lo ascolta, non abbiamo ulteriori elaborazioni.
class OtherSubEntity{ void listen(SubEntityEvent event){ data = SomeCPUIntenseCalc(); apply(SomeCPUIntenseCalcHappened(data)); } void when(SomeCPUIntenseCalcHappened event){ //just modify local fields //used also in event sourcing rehydration } }
Domande:
- Poiché AggreagateRoot è responsabile del salvataggio di tutti gli eventi nell'archivio eventi, come può sapere dell'esistenza di tutti questi eventi secondari verificatisi nella struttura ad albero.
- In questa transazione abbiamo generato 2 eventi. Dovremmo archiviarli all'interno dell'evento come una serie di eventi, o dovremmo memorizzarli semplicemente un evento dopo l'altro. Affinché AR sia in uno stato coerente, entrambi gli eventi devono essere applicati in un'unica transazione.
- In OtherSubEntity abbiamo il metodo di ascolto che ascolta SubEntityEvent. Dal momento che sulla reidratazione dall'archivio degli eventi chiameremo SubEntity.when (evento SubEntityEvent), come impedire che OtherSubEntity.listen venga chiamato contemporaneamente?
- Poiché la radice aggregata deve inviare 1 messaggio risultante lungo la pipeline (nel mio caso il messaggio AMQP), suppongo che questo messaggio sarà in realtà la proiezione di questi eventi a 2 domini - fondamentalmente un DTO del modello letto. Dove dovrei creare questo modello? Qualcosa di simile come modello letto solo con la propagazione?