How should I perform updates on nested children of an Aggregate Root?
Should I find the child object by traversal of associations and perform the update on it directly, or should I add a method on the Aggregate Root that takes care of it?
An example
I'm modelling an old project at our company which is a system we use to perform searches of customers against a suspicious person list:
The model
- We run a
Batch Search
every night - The
Batch Search
contains a list ofSearches
for it. - Each
Search
contains a list ofMatches
and is associated with oneCustomer
The process
- We check each
Match
and mark it as confirmed if it was a confirmed match. - We also tick a checkbox for each
Search
if all it'sMatches
where inspected
The caveat
A Search
can also run standalone, as in – not being a part of a Batch Search
. In that case the Search
naturally becomes the Aggregate Root.
Question
How should I be performing the update operations on the child items? The blue book states that all updates to children must go through the Aggregate Root.
There are 2 ways to perform this update:
Option 1
Traverse the graph and find the child object and perform the operation directly on it.
batchSearch = batchSearchRepo.find(1);
search = batchSearch.findSearch(5);
match = search.getMatch(3);
match.markConfirmed();
batchSearchRepo.save(batchSearch);
Option 2
Add a method on the Aggregate Root
batchSearch = batchSearchRepo.find(1);
search = batchSearch.markSearchMatchAsConfirmed(5, 3);
batchSearchRepo.save(batchSearch);
Which of the 2 update methods is more appropriate and why?
Best Answer
Aggregate roots exist to protect the data within them. If you tear the aggregate roots internal structures and do operations on the internals directly without incorporating the aggregate root, the aggregate root can no longer validate the operation is valid.
In DDD the second option is not only more appropriate, it is the only correct way to go (as stated in the quote you posted).
When you however encounter the nesting that you have, you could also ask yourself a question whether your design is 100% correct.
BatchSearch
aggregate roots on their own?Search
exist outside of the boundary ofBatchSearch
?Search
affect aBatchSearch
?If you answered yes to questions 1 and 2 and no to the third question, you have already eliminated one entire level on nesting and can now access a
Search
directly as a separate aggregate root. With this in mind, could you maybe to the same for aMatch
?