I have an aggregate Organization
which can have several addresses. So we have modeled this OrganizationDeliveryAddress
as an Aggregate Member. On the OrganizationDeliveryAddress
we command and event sourcing handlers for the entity itself.
Here's my current implementation:
@Aggregate
public class Organization {
private @AggregateIdentifier
@NonNull UUID organizationId;
@AggregateMember
private final List<OrganizationDeliveryAddress> deliveryAddresses = new ArrayList<>();
@CommandHandler
public UUID on(AddOrganizationDeliveryAddressCommand command) {
val addressId = UUID.randomUUID();
val event = new OrganizationDeliveryAddressAddedEvent(command.getOrganizationId(), addressId, command.getAddress());
AggregateLifecycle.apply(event);
return addressId;
}
@EventSourcingHandler
public void on(OrganizationDeliveryAddressAddedEvent event) {
val address = new OrganizationDeliveryAddress(event.getOrganizationDeliveryAddressId(), false);
deliveryAddresses.add(address);
}
}
public class OrganizationDeliveryAddress {
private @EntityId
@NonNull UUID organizationDeliveryAddressId;
@CommandHandler
public void on(RemoveOrganizationDeliveryAddressCommand command) {
AggregateLifecycle.apply(new OrganizationDeliveryAddressRemovedEvent(command.getOrganizationId(),
command.getOrganizationDeliveryAddressId()));
}
@EventSourcingHandler
public void on(@SuppressWarnings("unused") OrganizationDeliveryAddressRemovedEvent event) {
if (organizationDeliveryAddressId.equals(event.getOrganizationDeliveryAddressId())) {
AggregateLifecycle.markDeleted();
}
}
}
We want to remove one of the addresses, but it looks like not just the address, but the entire aggregate is deleted.
So here's my question: How can I instruct Axon Framework to remove the OrganizationDeliveryAddress
Aggregate Member?
The AggregateMember
is not an Aggregate per se but just a member of another Aggregate. This is why if you call AggregateLifecycle.markDeleted();
it will mark the Aggregate itself as deleted.
To 'delete' an AggregateMember
you should do the opposite as adding it, which means you can have an @EventSourcingHandler
method on your Aggregate listening to the OrganizationDeliveryAddressRemovedEvent
. This method would be responsible to find the right DeliveryAddress on your AggregateMember (deliveryAddresses
) or even better a Map
as you will see below and simply remove it from that. A pseudo-code could be something like this:
// Organization.java
...
@AggregateMember
private final Map<UUID, OrganizationDeliveryAddress> deliveryAddressItToDeliveryAddress = new HashMap<>();
...
@EventSourcingHandler
public void on(@SuppressWarnings("unused") OrganizationDeliveryAddressRemovedEvent event) {
Assert.isTrue(deliveryAddressItToDeliveryAddress.containsKey(event.getOrganizationDeliveryAddressId()), "We do not know about this address");
deliveryAddressItToDeliveryAddress.remove(event.getOrganizationDeliveryAddressId());
}