skip to content

How does @MappedCollection map child entities to a child table in Spring Data JDBC?

level: middleimportance: should knowfreq 50%

answer

  1. idColumn = FK back to root
  2. keyColumn = List index / Map key
  3. Set needs no keyColumn
  4. child often needs no @Id
  5. @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 s

A 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 lines
java
class 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

for a junior

Know that @MappedCollection maps a collection to a child table.

for a middle

Explain idColumn (back-reference FK) and keyColumn (List index / Map key), and that Set needs no keyColumn.

for a senior

Contrast with @Embedded, discuss when children need no @Id, and the load/save cost of wide child collections.

for a principal

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

context