When you implement DDD Aggregates using just “regular” Spring JPA (not e.g. Spring Modulith), there are a number of practical tips to consider
If inner (nested) entities would have repositories, they could be accessed directly,
bypassing the aggregate root. This is a violation of aggregate rules. Instead, you
can use a cascade
instruction like this:
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private List<ShoppingCartPart> shoppingCartParts = new ArrayList<>();
This means that all operations (create, save, change, delete, …) are “looped through”
to the inner entity. It is sufficient to execute save(...)
, delete(...)
etc. on
the ShoppingCart
aggregate root.
The additional parameters have the following meaning:
orphanRemoval = true
deletes “leftover” shopping cart items that have been
removed from the collectionfetch = FetchType.EAGER
ensures that lazy loading is not used; this is somewhat
safer if the shopping cart is also used in other places (possibly outside the
current DB session).Aggregates need to be “transaction boundaries” in order to be decoupled of each other. One essential rule is to reference other aggrates only by ID reference, not by object reference. This prevent the temptation to modify other aggregates in the same transaction. It also helps keeping queries small.
A practical guide for such IDs can be found here.