Card 04/ 07

ConceptDifficulty: Advanced1 min

Aggregate Roots in Spring Data JDBC: One Repository per Aggregate

The entity a repository is written for owns everything inside it, and nothing inside gets a repository of its own.

An aggregate is a group of objects that belong together and are always loaded and saved as one unit, such as a booking and its stops. The aggregate root is the one object in the group that the outside world refers to, here the booking. Spring Data JDBC builds on this idea: a repository is written for an aggregate root, and everything the root owns travels with it.

The rule that follows is one repository per aggregate root. A booking's stops have no repository of their own; you change a stop by loading the booking, changing it, and saving the booking. A repository for stops would give a second, independent way to change data that is only consistent as a whole.

Saving an aggregate in Spring Data JDBC writes the root and its children together, and loading it reads them together. There is no lazy loading (fetching related rows only when the code first reads them) and no persistence context (JPA's record of the entities it is tracking in the current transaction) to make a child appear later, which is why the boundary has to be decided up front.

JPA has no equivalent restriction. You can write a repository for any @Entity, parent or child, which is flexible, and is also part of why a JPA domain's real shape is harder to see from its repositories alone.

So choosing Spring Data JDBC means deciding your aggregates first: which objects belong together, and which one the rest of the application talks to.