liveBook · Manning

Ternary relationship

As explained in Java Persistence with Spring Data and Hibernate epub

A ternary relationship is a relationship that simultaneously connects instances of three participating entity or object types.

A ternary relationship connects Category, Item, and User through one association. In a relational schema, the link table therefore contains CATEGORY_ID, ITEM_ID, and USER_ID foreign-key columns. section 9.3.3 section 9.3.2

A compact JPA/Hibernate mapping models the link as an @Embeddable CategorizedItem stored in Category’s @ElementCollection. Its @ManyToOne fields reference Item and User, while Category supplies the third participant. section 9.3.3

This mapping has important persistence consequences:

  • Add a CategorizedItem to Category.categorizedItems to create the association, and remove it to break the link; extra cascading configuration is unnecessary. section 9.3.3
  • Use CATEGORY_ID and ITEM_ID as the composite primary key; @NotNull prevents those properties from becoming key columns, but generated SQL still needs manual NOT NULL constraints. section 9.3.3
  • Accept unidirectional navigation: the embeddable cannot be shared by Item, so querying Category explicitly is required when starting from an Item. section 9.3.3

Creating three-party links

Create CategorizedItem(someUser, someItem) and add it to someCategory; create another link for a second Item, then add a third link for that Item under another Category.

Path: manytomany-ternary/src/main/java/com/manning/javapersistence
 /ch09/manytomany/ternary/CategorizedItem.java
 
@Embeddable
public class CategorizedItem {
    @ManyToOne
    @JoinColumn(
        name = "ITEM_ID",
        nullable = false, updatable = false
    )
    private Item item;
    @ManyToOne
    @JoinColumn(
        name = "USER_ID",
        updatable = false
    )
    @NotNull                                               #1
    private User addedBy;
    @Column(updatable = false)
    @NotNull                                               #1
    private LocalDateTime addedOn = LocalDateTime.now();
    public CategorizedItem() {
    }
    public CategorizedItem(User addedBy,
                           Item item) {
        this.addedBy = addedBy;
        this.item = item;
    }
    //  . . .
}
#1 The <kbd>@NotNull</kbd> annotations do not generate an SQL constraint, so the annotated fields will not be part of the primary key.

Inspect the embeddable class to see how Item, User, timestamps, join columns, and validation annotations shape the link table. section 9.3.3

How Java Persistence with Spring Data and Hibernate epub covers it

How deep it goes
Explains annotations, composite-key consequences, lifecycle operations, schema constraints, and navigation limits, but not bidirectional embeddable mapping.
Examples
Uses Category, Item, User, CategorizedItem, CATEGORY_ITEM, and a repository query returning categories for an Item.
What it assumes
Assumes familiarity with Java entities, JPA association annotations, collections, foreign keys, and composite primary keys.
What you can do after
Build it from scratch with JPA/Hibernate annotations, manage links through a collection, and query associations from the non-owning side.
How it connects
Connects many-to-many associations, intermediate entities, embeddable components, element collections, and many-to-one associations.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Java Persistence with Spring Data and Hibernate epub. The section links point to the parts of the book it draws on.