Это очень распространенный вопрос, поэтому этот ответ основан на статье, которую я написал в своем блоге.
Один ко многим
Отношение таблиц "один ко многим" выглядит так:

В системе реляционной базы данных отношение таблиц «один ко многим» связывает две таблицы на основе 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 аннотация
В JPA лучший способ отобразить связь таблицы «один-ко-многим» - использовать @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аннотацию, не означает, что она должна быть параметром по умолчанию для всех отношений базы данных « один ко многим» .
Проблема с коллекциями JPA в том, что мы можем использовать их только тогда, когда в них достаточно мало элементов.
Лучший способ сопоставить @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<>();
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идентификатор объекта.
Отображение выглядит так:
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class 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;
}
}
Таким образом, 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отношения с tagID таблицы 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<>();
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<>();
@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Объект имеет уникальный бизнес - ключ , который отмечается с Hibernate-специфической @NaturalIdаннотацией. В этом случае уникальный бизнес-ключ является лучшим кандидатом для проверки равенства .
mappedByАтрибут postsассоциации в Tagотметках сущностей , что в этом двунаправленной связи, то Postпредприятие имеет ассоциацию. Это необходимо, поскольку только одна сторона может владеть отношением, и изменения распространяются в базу данных только с этой конкретной стороны.
SetЯвляется предпочтительным, как использование Listс @ManyToManyменее эффективным.
Для получения дополнительных сведений о наилучшем способе сопоставления @ManyToManyотношений с JPA и Hibernate ознакомьтесь с этой статьей .