How to check constraints involving multiple aggregates ?

Hi,

While executing a command on a aggregate, I wonder how to check constraints that involve accessing the state of other aggregates ?
For example how to ensure that the combination of (name, login and email) is unique among all aggregates of type User, in a constructor command, or in other commands that can modify one of these fields ?

Regards,

Mael

Hi Mael,

conceptually, an aggregate is a consistency boundary, which means invariants outside of this boundary are eventually consistent.
In Axon, the best way to validate cross-aggregate invariants is using an Event Handler or Saga. When an illegal value is detected, it would generate a compensating transaction to correct the action.

Alternatively, you could maintain a registry in which a command ‘claims’ a value it’s about to use. If the claim succeeds, it must be the only one. If the command fails for some reason, you should release the claim. Don’t claim in the same transaction as the rest of the activity, just to make sure the claim is visible to other threads.

Hope this helps.
Cheers,

Allard

Hi Allard,

Thanks for your answer !

Ok in DDD transaction boundaries are limited to one aggregate, and so we can only have eventual consistency in processing involving multiple aggregates, but I wonder if in some use cases we should not consider that aggregate boundaries change (not static) between use cases, at least conceptually.

For ex, in this article : http://www.udidahan.com/2009/06/29/dont-create-aggregate-roots/ Udi says that most of the time new aggregates are created from another one, that can also perform some checking during the creation process (in his exemple check that name contains no space).

For exemple in my application, the administrator can register new Users (Aggregate Root), but the login and email must be unique among all users in the repository.
Eventual consistency could be a problem here, as for example the “retrieve lost password from email” function wouldnt work if 2 users had the same email at the same time (low probability but still exists)

Does it make sense to have another higher level aggregate root “UserRegistry” that handle the creation of new users ? In that use case (user creation), the aggregate root would not be User but UserRegistry. And in another use case that doesn’t involve the modification of the user email, the aggregate root would be the User.
So, even if statically the 2 classes are declared as AggregateRoot (no choice as java is a static language), conceptually I wonder if in fact aggregate root boundaries should depend on use case, and if so, could we use axon framework this way, by making an AR “UserRegistry” handle the creation of another AR “User”, in the same transaction (no eventual consistency in this case) ?

In fact in this use case, the UserRegistry should not contains the collections of all Users as it would be inefficient. It should contains only the minimum info : UserId and email.
So in fact the user in the registry is not the same “User” class, but a “UserRegistryEntry”, that is not an AR, but an entity.
In this case we would call “registerNewUser” on the registry first, and an EventHandler would then create the User AR (in separate transactions)
But my problem here is that I would like to ensure that the only way to create a new User is to call a command on the UserRegistry AR, and not directly on the User AR. If a new developper in the team find a command “create” on the User AR, he could be tempted to use it without knowing that he must use the “registerNewUser” of the UserRegistry AR.

Regards,

Mael

Hi,

set validation is a topic that has been discussed a few times in this group. Check out this message/thread for some background: https://groups.google.com/d/msg/axonframework/jcS0kWWGE4M/cGXkhsqgsqkJ

or this one:
https://groups.google.com/d/msg/axonframework/RZ4D6kzbPjU/1azyCD0gcE0J

Hope this helps.
Cheers,

Allard