-
Type:
New Feature
-
Resolution: Fixed
-
Priority:
Major - P3
-
Affects Version/s: None
Summary
Support entity associations and joins involving an entity whose primary key is a composite, declared with @EmbeddedId on a plain @Embeddable and stored as an _id sub-document (the model introduced by HIBERNATE-207).
Scope
- Composite foreign keys: a @ManyToOne (or other FK-bearing mapping) whose target entity has a composite key. Boot currently rejects an association as an id component and has no layout for a composite FK. Open design question: where the FK lives in the document, per-component columns or a sub-document, in a canonical component order (the _id uniqueness semantics are field-order-sensitive, per
HIBERNATE-207). - HQL joins over composite keys: mapped association joins (@ManyToOne / @OneToMany) and explicit entity joins with ON conditions, where either side may have a composite key.
Out of scope, tracked separately: @IdClass (HIBERNATE-235), non-scalar id component (HIBERNATE-236), @MapsId / derived identity (HIBERNATE-237).
Current state
Verified by probe against a composite-keyed Book and Review sharing component names (publisherId, bookNo):
SELECT b.id, r.id FROM Book b JOIN Review r ON b.id = r.id
fails with FeatureNotSupportedException "TODO-HIBERNATE-168" from AbstractMqlTranslator.buildJoinStages. The joined entity's table group carries a nested TableGroupJoin, which Hibernate materializes for the embeddable id, and the HIBERNATE-168 guard rejects all nested table group joins (its own scope is association navigation inside ON, a different trigger). Adding per-component conjuncts (ON b.id = r.id AND b.title = r.comment) fails identically; the guard runs before any predicate translation.
Notes on what already exists:
- Compound ON conditions between scalar-key entities work (
HIBERNATE-164, $lookup with $expr).HIBERNATE-164covers only scalar keys on both sides of each conjunct; composite keys are not covered. - Comparisons between whole composite ids already decompose into per-component equalities (the SqlTuple row-value path from
HIBERNATE-210/HIBERNATE-207), and inside a $lookup sub-pipeline the ON predicate reuses the general visitors with outer columns bound to let variables. That machinery is untested for composite ids only because translation never reaches it.
Work items
- Boot: define the composite-FK document layout, and lift the association-component rejection for this case.
- Translator: let buildJoinStages accept the embeddable-id nested table group, and confirm the emitted $lookup decomposes a whole-composite ON predicate into per-component $expr conjuncts.
- Tests: the probe (Book / Review entity join, whole-id ON, and ON with an added conjunct) becomes the first test; extend to mapped @ManyToOne storage and association joins as boot support lands.