How to create new aggregate root in CQRS

cqrsdomain-driven-designentityevent-programmingevent-sourcing

How should we create new aggregate roots in cqrs architecture? In this example I want to create new aggregate root AR2 that holds reference to first one AR1.

I'm creating AR2 using AR1 method as starting point. So far I see few options:

  1. Inside method in AR1 createAr2RootOpt1 I could call new AR2() and save this object to db imediatelly using domain service that has acces to repository.
  2. I could emit event in first aggregate root eg. SholdCreateAR2Event and then have stateless saga that reacts on this and issues command CreateAR2Command which is then handled and actually creates AR2 and emits AR2CreatedEvent. In case of using event sourcing SholdCreateAR2Event would not be preserved in event store, since it does not affect the state of first aggregate root. (Or should we still save this in event store?)

    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());
        }
    }
    

Which is more proper way to do this?

Best Answer

I think that option no. 2 is the solution, with a small but important modification: AR1 should not emit a event who's purpose is to create the AR2, instead it should emit a AR1WasCreated event. This event should be persisted in the event store, as it is an important event marking the birth of AR1. Then, a Saga whould listent for AR1WasCreated event and generate a command to create AR2: CreateAR2Command.

Option no.1 is very wrong. You should never inject that kind of domain service in an Aggregate. Aggregates should be pure, with no side effects other that the generation of events.

P.S. I never emit events from the constructor of the Aggregate as there is a distinction between creating an instance of an object (in the programming language sense) and the creation (the birth if you want) of an Aggregate. I emit events only from a handle method (when handling a command).

Related Topic