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.