I’m applying the DDD Aggregate pattern in a Spring Boot application. For example, Order is the aggregate root of OrderItem, and they are mapped like this:
@Entity
public class Order {
@Id
private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> orderItems = new ArrayList<>();
public void renameOrderItem(Long itemId, String newName) {
orderItems.stream()
.filter(item -> item.getId().equals(itemId))
.findFirst()
.orElseThrow()
.rename(newName);
}
}
@Entity
public class OrderItem {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Order order;
private String name;
public void rename(String newName) {
this.name = newName;
}
}
✅ Problem
According to the DDD Aggregate rules, OrderItem must be modified through its root, Order.
So even for updating just one OrderItem, I need to load the entire Order and call order.renameOrderItem(...).
However, this leads to a few issues:
- Without fetch join → Accessing orderItems causes an N+1 problem.
- With fetch join → All OrderItems are loaded, even if I only need one → memory inefficiency.
- With orphanRemoval=true → If I only partially load OrderItems and then save the Order, the other items might get deleted.
❓ My Question
How can I safely modify an OrderItem through its aggregate root Order while still avoiding N+1 queries and memory waste when using Spring JPA and OneToMany mapping?
💡 What I’ve considered
• Keep OrderItemEntity and domain model OrderItem separate
• Load only the OrderItemEntity I need
• Construct an Order domain model containing just this OrderItem
• Run business logic via Order.findItem(id).rename()
• Convert the updated domain model back to entity and save
This way I preserve aggregate integrity, but it results in additional conversion logic and a more complex repository layer.
❓ TL;DR
How do you respect aggregate encapsulation in DDD while also avoiding fetch-join-all or N+1 problems with JPA?
I’m especially interested in real-world solutions or architecture patterns that you’ve used in production.
I’ve seen several related questions, but none of them provided a clear answer.