Relationships between aggregates root

I have a tow aggregates:
A=aggregates root
B= aggregates root

A and B have a Composition relationship
how Axon do this type of relationship?


In DDD we model the domain using several aggregates (root + entities). One such aggregate or entity can hold a reference to another aggregate root through its id.

In axon, I see the concept of aggregates and member entities, but I do not see the notion of references to other aggregates.

Hi Zeynab,

To coordinate between aggregates, you can use sagas. We sometimes call the same component process manager, which might be less confusing.

In short, a saga can hold references to multiple aggregates. A specific event processor backs it, which will check for each event if there is a saga that should handle it or whether a new saga should be created.

1 Like

Thank you, I will do it.

Can you give me an example? please

Please give me one example for this subject

Sure, this is from an example project,

package com.example.axon.saga;

import com.example.axon.api.MarkValidationFailedCommand;
import com.example.axon.api.MarkValidationSucceededCommand;
import com.example.axon.api.ProductCreatedEvent;
import com.example.axon.api.StartValidationCommand;
import com.example.axon.api.ValidateDelayedCommand;
import com.example.axon.api.ValidateDelayedEvent;
import com.example.axon.api.ValidateTrueCommand;
import com.example.axon.api.ValidateTrueEvent;
import com.example.axon.api.ValidationEnded;
import com.example.axon.api.ValidationStarted;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.eventhandling.scheduling.EventScheduler;
import org.axonframework.eventhandling.scheduling.ScheduleToken;
import org.axonframework.modelling.saga.EndSaga;
import org.axonframework.modelling.saga.SagaEventHandler;
import org.axonframework.modelling.saga.SagaLifecycle;
import org.axonframework.modelling.saga.StartSaga;
import org.axonframework.spring.stereotype.Saga;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Duration;
import java.util.UUID;

import static java.util.Objects.isNull;

public class ValidatingSaga {

    private String productId;
    private ScheduleToken scheduleId;
    private boolean alwaysTrueValidated = false;
    private boolean delayedValidated = false;

    CommandGateway commandGateway;

    EventScheduler eventScheduler;

    void setCommandGateway(CommandGateway commandGateway) {
        this.commandGateway = commandGateway;

    void setDeadlineManager(EventScheduler eventScheduler) {
        this.eventScheduler = eventScheduler;

    @SagaEventHandler(associationProperty = "productId")
    public void handle(ProductCreatedEvent event) {
        this.productId = event.getProductId();

    @SagaEventHandler(associationProperty = "productId")
    public void handle(ValidationStarted event) {
        String validateTrueId = UUID.randomUUID().toString();
        String validateDelayedId = UUID.randomUUID().toString();
        SagaLifecycle.associateWith("validateTrueId", validateTrueId);
        SagaLifecycle.associateWith("validateDelayedId", validateDelayedId);
        scheduleId = eventScheduler.schedule(

    @SagaEventHandler(associationProperty = "validateTrueId")
    public void handle(ValidateTrueEvent event) {
        if (event.isSuccess()) {
            alwaysTrueValidated = true;
        } else {

    @SagaEventHandler(associationProperty = "validateDelayedId")
    public void handle(ValidateDelayedEvent event) {"validating delayed event: {} while validated: {}", event, delayedValidated);
        if (event.isFromScheduler()){
            scheduleId = null;
        if (event.isSuccess()) {
            delayedValidated = true;
        } else {

    private void bothCompleteCheck() {
        if (alwaysTrueValidated && delayedValidated) {

    private void markFailed() {

    @SagaEventHandler(associationProperty = "productId")
    public void handle(ValidationEnded event) {
        if (!isNull(scheduleId)) {
            scheduleId = null;
  "Set scheduleId to null.");
        } else {
  "No deadline to cancel.");
        }"Saga with product id: [{}] was ended.", productId);

    public String getProductId() {
        return productId;

    public ScheduleToken getScheduleId() {
        return scheduleId;

    public boolean isAlwaysTrueValidated() {
        return alwaysTrueValidated;

    public boolean isDelayedValidated() {
        return delayedValidated;

Great example. But could he have meant something like a one-to-one, one-to-many, many-to-many relationship type of thing by “Composition” ?


public class Boss {

	private UUID bossId;

        String name;

	private List<Employee> employees = new ArrayList<Employee>;

	public void handle(ListEmployeesCommand command) {
        	AggregateLifecycle.apply(new ListEmployeesEvent(bossId, getEmployees()));

    public void on(GetEmployeesEvent event) {
        return getEmployees();

    // getter, setter
    public ArrayList<Employee> getEmployees() {
        return this.employees


public class Employee {

	private UUID employeeId;

	private UUID bossId;

       // ...