Cascading deletes

Hello Axon users,

I think that a typical problem that people have is to delete/update a bunch of aggregates when someone else does.
I have an Aggregate referred by others, and when it goes, eventually all the others must update. E.g. if I unsubscribe from facebook, all my facebook friends should lose me as a friend.

Resorting to the read layer to find those other seems quick enough, but it’s not 100% safe.

The alterative seems instead a lot harder. Maybe to keep a Saga to track the inverse references, send the update commands once there is the delete, and keep sending it for any new reference that is created after it.

There are more possibilities. Hopefully something simpler… Anyone has a take on this?

Cheers

Hi Andrea,

using the read model is maybe not 100% safe, but isn’t 99,9% enough? The read model is much cheaper, easier and faster to use than Sagas.
Sagas will add some complexity that you most likely don’t really need.

Cheers,

Allard

There a lot of options to handle this with the read model. Which one is preferred or is there another option?

Note: the Java code might not be fully correct.

Option 1 dispatch new commands in command handler:

@CommandHander
public void handle(UserUnsubscribe command) {
Collection users = userQueryRepository.getWithFriend(command.userId);
for (User user : users) {
commandBus.dispatch(new RemoveFriendCommand(user.id, command.userId));
}
User user = userRepository.load(command.userId);
user.unsubscribe();
}

Option 2 dispatch new commands in event handler:

@CommandHander
public void handle(UserUnsubscribe command) {
User user = userRepository.load(command.userId);
user.unsubscribe(); // publishes UserUnsubscribedEvent
}

@EventHandler
public void handle(UserUnsubscribedEvent event) {
Collection users = userQueryRepository.getWithFriend(event.userId);
for (User user : users) {
commandBus.dispatch(new RemoveFriendCommand(user.id, event.userId));
}
}

Option 3 only update query model:

@CommandHander
public void handle(UserUnsubscribe command) {
User user = userRepository.load(command.userId);
user.unsubscribe(); // publishes UserUnsubscribedEvent
}

@EventHandler
public void handle(UserUnsubscribedEvent event) {
Collection users = userQueryRepository.getWithFriend(event.userId);
for (User user : users) {
userQueryRepository.removeFriend(user.id, event.userId);
}
}

Option 3 doesn’t even update the other user’s aggregates.

Thanks for the input guys.