पाठ 11 / 25

Many-to-Many and One-to-One

Map many-to-many with a join table or an explicit entity, and one-to-one relationships.

Join tables and shared keys

@ManyToMany maps a relationship through a join table (@JoinTable with joinColumns and inverseJoinColumns): students and courses, products and tags. Use a Set rather than a List for many-to-many collections, because Hibernate handles List bags inefficiently on removal (deleting and reinserting all rows). As soon as the relationship needs its own attributes (enrolment date, grade, quantity), replace @ManyToMany with an explicit entity for the association (Enrolment) and two @ManyToOnes; this is also easier to query and evolve, and many teams prefer it from the start. @OneToOne maps one-to-one relationships, such as a user and their profile. The most efficient mapping shares the primary key with @MapsId, so the child's ID equals the parent's; a separate foreign key column also works. Remember that @OneToOne and @ManyToOne default to eager fetching; mark them LAZY. A bidirectional @OneToOne inverse side often cannot be lazy without bytecode enhancement, a common performance surprise.

Tags as many-to-many, enrolment as an explicit entity, profile with @MapsId

Choose the explicit entity when the link has data.

@Entity
public class Article {
    @Id @GeneratedValue private Long id;

    @ManyToMany
    @JoinTable(name = "article_tags",
               joinColumns = @JoinColumn(name = "article_id"),
               inverseJoinColumns = @JoinColumn(name = "tag_id"))
    private Set<Tag> tags = new HashSet<>();      // Set, not List
}

@Entity
public class CourseEnrolment {                    // association with attributes
    @Id @GeneratedValue private Long id;
    @ManyToOne(fetch = FetchType.LAZY, optional = false) private Student student;
    @ManyToOne(fetch = FetchType.LAZY, optional = false) private Course course;
    private LocalDate enrolledOn;
    private String grade;
}

@Entity
public class UserProfile {
    @Id private Long id;                           // same value as the user's id
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private AppUser user;
    private String bio;
}

A guest list versus a ticket stub

A plain many-to-many is a guest list linking guests to parties. Once you need to record which seat each guest had and what they paid, you need a ticket stub for each pairing: an entity of its own.

त्वरित जाँच: A student-course relationship needs to store the grade. How should it be mapped?

  • @ManyToMany with a List
  • An explicit association entity (e.g. Enrolment) with two @ManyToOne relationships
  • A comma-separated column
  • @OneToOne
Answer

An explicit association entity (e.g. Enrolment) with two @ManyToOne relationships — Attributes on the link require an entity for the association.