Це дуже поширене питання, тому ця відповідь заснована на цій статті, яку я написав у своєму блозі.
Один до багатьох
Співвідношення таблиці «один до багатьох» виглядає так:

У системі реляційних баз даних взаємозв'язок таблиці один на багато пов'язує дві таблиці на основі Foreign Keyстовпця у дочірній частині, який посилається Primary Keyна батьківський рядок таблиці.
На діаграмі таблиці вище, post_idстовпець у post_commentтаблиці має Foreign Keyвідношення до стовпця postідентифікатора Primary Keyтаблиці:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
@ManyToOne анотація
Найкращий спосіб зіставити співвідношення таблиці «один до багатьох» - це використання @ManyToOneанотації.
У нашому випадку дочірнє об'єднання PostCommentвідображає post_idстовпчик "Зовнішній ключ" за допомогою @ManyToOneанотації:
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
@ManyToOne(fetch = FetchType.LAZY)
private Post post;
}
Використання @OneToManyпримітки JPA
Тільки тому, що у вас є можливість використовувати @OneToManyанотацію, це не означає, що це має бути варіантом за замовчуванням для кожного " для багатьох" співвідношення бази даних . Проблема з колекціями полягає в тому, що ми можемо ними користуватися лише тоді, коли кількість дочірніх записів досить обмежена.
Найкращий спосіб відобразити @OneToManyасоціацію - покладатися на @ManyToOneсторону для поширення всіх змін стану сутності:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
}
У материнської сутності Postє два корисні методи (наприклад, addCommentта removeComment), які використовуються для синхронізації обох сторін двонаправленого об'єднання. Ви завжди повинні надавати ці методи кожного разу, коли працюєте з двосторонньою асоціацією, оскільки, в іншому випадку, ви ризикуєте дуже тонкими проблемами поширення держави .
Односторонньої @OneToManyасоціації слід уникати, оскільки вона менш ефективна, ніж використання @ManyToOneабо двостороння @OneToManyасоціація.
Щоб отримати докладнішу інформацію про найкращий спосіб зіставити @OneToManyстосунки з JPA та Hibernate, перегляньте цю статтю .
Один до одного
Співвідношення таблиці «один на один» виглядає так:

У системі реляційних баз даних взаємозв'язок таблиці один на один пов'язує дві таблиці на основі Primary Keyстовпця у дочірній, що також є Foreign Keyпосиланням Primary Keyна батьківський рядок таблиці.
Тому можна сказати, що дочірня таблиця ділиться Primary Keyз батьківською таблицею.
На діаграмі таблиці вище, idстовпець у post_detailsтаблиці також має Foreign Keyвідношення до стовпця postтаблиці id Primary Key:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Використання JPA @OneToOneз @MapsIdпримітками
Найкращий спосіб зіставити @OneToOneвідносини - це використовувати @MapsId. Таким чином, вам навіть не потрібна двонаправлена асоціація, оскільки ви завжди можете отримати PostDetailsоб'єкт, використовуючи Postідентифікатор сутності.
Відображення виглядає приблизно так:
[код мови = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") публічний клас PostDetails {
@Id
private Long id;
@Column(name = "created_on")
private Date createdOn;
@Column(name = "created_by")
private String createdBy;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "id")
private Post post;
public PostDetails() {}
public PostDetails(String createdBy) {
createdOn = new Date();
this.createdBy = createdBy;
}
//Getters and setters omitted for brevity
} [/ код]
Таким чином, idвластивість виконує функції "Первинний ключ" та "Зовнішній ключ". Ви помітите, що @Idстовпець більше не використовує @GeneratedValueанотацію, оскільки ідентифікатор заповнений ідентифікатором postасоціації.
Щоб отримати докладнішу інформацію про найкращий спосіб зіставити @OneToOneстосунки з JPA та Hibernate, перегляньте цю статтю .
Багато-до-багатьох
Співвідношення таблиці «багато до багатьох» виглядає так:

У реляційній системі баз даних багато-багато-багато табличних зв’язків пов'язують дві батьківські таблиці через дочірню таблицю, яка містить два Foreign Keyстовпці, що посилаються на Primary Keyстовпці двох батьківських таблиць.
На діаграмі таблиці вище, post_idстовпець у post_tagтаблиці також має Foreign Keyзв'язок із стовпцем postідентифікатора Primary Keyтаблиці:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
І, tag_idстовпець у post_tagтаблиці має Foreign Keyвідношення до стовпця tagідентифікатора Primary Keyтаблиці:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Використання @ManyToManyкарти JPA
Ось як можна зіставити many-to-manyвзаємозв’язок таблиці з JPA та Hibernate:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private Set<Tag> tags = new HashSet<>();
//Getters and setters ommitted for brevity
public void addTag(Tag tag) {
tags.add(tag);
tag.getPosts().add(this);
}
public void removeTag(Tag tag) {
tags.remove(tag);
tag.getPosts().remove(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Post)) return false;
return id != null && id.equals(((Post) o).getId());
}
@Override
public int hashCode() {
return 31;
}
}
@Entity(name = "Tag")
@Table(name = "tag")
public class Tag {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String name;
@ManyToMany(mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
//Getters and setters ommitted for brevity
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Tag tag = (Tag) o;
return Objects.equals(name, tag.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
tagsОб'єднання в Postсутності тільки визначає PERSISTі MERGEкаскадні типів. Як пояснено в цій статті , REMOVE перехід стану сутності не має жодного сенсу для @ManyToManyасоціації JPA, оскільки це може спровокувати вилучення ланцюга, що врешті-решт знищить обидві сторони асоціації.
- Як пояснено в цій статті , методи додавання / видалення утиліти є обов'язковими, якщо ви використовуєте двосторонні асоціації, щоб ви могли переконатися, що обидві сторони асоціації синхронізовані.
- Суб'єкт
Postгосподарювання використовує ідентифікатор сутності для рівності, оскільки йому не вистачає жодного унікального бізнес-ключа. Як пояснено в цій статті , ви можете використовувати ідентифікатор сутності для рівності, якщо ви переконаєтесь, що він залишається послідовним для всіх переходів стану сутності .
- Суб'єкт
Tagгосподарювання має унікальний бізнес-ключ, який позначений @NaturalIdанотацією, що стосується сплячого режиму . У цьому випадку унікальний бізнес-ключ є найкращим кандидатом на перевірку рівності .
mappedByАтрибут postsасоціації в Tagпозначках сутностей , що в цьому двобічної зв'язку, то Postпідприємство має асоціацію. Це потрібно, оскільки лише одна сторона може володіти відносинами, а зміни передаються лише до бази даних саме з цієї сторони.
- Переважним
Setє те, що використання методу Listз @ManyToManyменш ефективним.
Щоб отримати докладнішу інформацію про найкращий спосіб зіставити @ManyToManyстосунки з JPA та Hibernate, перегляньте цю статтю .