How does @MappedCollection map child entities to a child table in Spring Data JDBC?
answer
- idColumn = FK back to root
- keyColumn = List index / Map key
- Set needs no keyColumn
- child often needs no @Id
- @Embedded = fields in parent row
basics
~20 s@MappedCollection maps a collection field on the root to a separate child table. Its idColumn is the foreign key back to the parent, and keyColumn holds the list index or map key so ordered/keyed collections round-trip correctly.
solid answer
~40 sA collection field of owned children maps to a child table via @MappedCollection. idColumn names the child table's foreign-key column that points back to the aggregate root's id — this back-reference is how children are tied to their parent (children often don't even need their own @Id). keyColumn is required for List (stores the position/index) and Map (stores the key); a Set needs neither because it is unordered. Single-child (one-to-one) references can also use @MappedCollection or the @Embedded/reference mechanisms. On load, Spring joins/queries the child table by the back-reference to reassemble the collection; on save it writes those child rows. Column and table names follow the configured NamingStrategy unless overridden.
code
java · 22 linesclass Order {
@Id Long id;
// List: keyColumn stores the index so order is preserved
@MappedCollection(idColumn = "order_id", keyColumn = "item_index")
List<OrderItem> items = new ArrayList<>();
// Set: no keyColumn (unordered)
@MappedCollection(idColumn = "order_id")
Set<Tag> tags = new HashSet<>();
}
class OrderItem { // no @Id needed: identified by order_id + item_index
String sku;
int qty;
}
/* order_item table:
order_id BIGINT -- idColumn, FK back to order.id
item_index INT -- keyColumn, the list position
sku VARCHAR
qty INT */go deeper
Know that @MappedCollection maps a collection to a child table.
Explain idColumn (back-reference FK) and keyColumn (List index / Map key), and that Set needs no keyColumn.
Contrast with @Embedded, discuss when children need no @Id, and the load/save cost of wide child collections.
Reason about naming strategy, aggregate size, and when to inline vs. split into child tables for performance and schema clarity.
**`@MappedCollection`** (in `org.springframework.data.relational.core.mapping`) tells Spring Data JDBC that a collection (or single reference) field on an aggregate holds **owned child entities** stored in a separate **child table**. **The back-reference (`idColumn`).** Child tables do not have a foreign-key *object*; instead the child table carries a column pointing back to the root's primary key. `idColumn` names that column. Example: `Order` (table `order`, PK `id`) owns `OrderItem` rows in table `order_item`; each `order_item` row has an `order_id` column = the owning order's id. So `@MappedCollection(idColumn = "order_id")`. Because children are identified *by this back-reference* plus their position/key, an owned child frequently needs **no `@Id` of its own**. **The key column (`keyColumn`).** Ordered or keyed collections need an extra column to preserve their structure: - `List<T>` — order matters, so `keyColumn` stores the **index** (0,1,2…). Required. - `Map<K,V>` — `keyColumn` stores the **map key**. Required. - `Set<T>` — unordered, so **no** `keyColumn` is needed (and Set gives no ordering guarantee). Without the key column a `List`/`Map` can't be reconstructed faithfully. **Naming.** If you omit attributes, column and table names come from the configured `NamingStrategy` (default: snake_case of the property/type). `@MappedCollection` lets you override the `idColumn` and `keyColumn` explicitly; the `@Table` annotation overrides a child's table name. **Single (one-to-one) references.** A non-collection reference to an owned entity is also a mapped relationship — you can annotate it with `@MappedCollection(idColumn = ...)` to name the back-reference column. Truly value-like data can instead be inlined with `@Embedded`, which stores the child's fields as extra columns *in the parent's own row* (no child table). **How it round-trips.** - **Load:** loading the root issues query(ies) against each child table filtered by the back-reference id, and for List/Map orders/keys by the key column. - **Save:** the root's children are written to the child table with the back-reference set to the root id (and key column populated for List/Map). **Gotchas.** (1) For a `List`, forgetting `keyColumn` breaks ordering. (2) `Set` order is not stable across loads. (3) Children referenced across *different* aggregates must NOT be modeled with `@MappedCollection` — use an id/`AggregateReference` instead. (4) Deep or wide child graphs mean big loads/saves — keep aggregates small.
- When can an owned child entity skip having its own @Id?When it is identified purely by the back-reference (idColumn) plus, for List/Map, the keyColumn. Since Spring rewrites all children on save, a child in a keyed/ordered collection needs no surrogate id of its own.
- What's the difference between @MappedCollection and @Embedded?@MappedCollection stores children in a separate child table linked by a back-reference. @Embedded inlines the referenced object's fields as extra columns in the parent's own row — no child table, one-to-one only.
saying these in an interview costs you the question
- Thinking idColumn is a column on the parent rather than the FK on the child
- Omitting keyColumn for a List and expecting stable ordering
- Using @MappedCollection for a cross-aggregate reference
- Assuming every child must have its own @Id