В каком случае вы используете @JoinTable
аннотацию JPA ?
В каком случае вы используете @JoinTable
аннотацию JPA ?
Ответы:
РЕДАКТИРОВАТЬ 2017-04-29 : Как указывали некоторые из комментаторов, в JoinTable
примере не требуется mappedBy
атрибут аннотации. Фактически, последние версии Hibernate отказываются запускаться, выводя следующую ошибку:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Давайте представим, что у вас есть названная сущность Project
и другая сущность, Task
и у каждого проекта может быть много задач.
Вы можете разработать схему базы данных для этого сценария двумя способами.
Первое решение - создать таблицу с именем Project
и другую таблицу с именем Task
и добавить столбец внешнего ключа в таблицу задач с именем project_id
:
Project Task
------- ----
id id
name name
project_id
Таким образом можно будет определить проект для каждой строки в таблице задач. Если вы используете этот подход, в ваших классах сущностей вам не понадобится таблица соединений:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
Другое решение - использовать третью таблицу, например Project_Tasks
, и сохранить отношения между проектами и задачами в этой таблице:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Project_Tasks
Таблица называется «Join Table». Чтобы реализовать это второе решение в JPA, вам необходимо использовать @JoinTable
аннотацию. Например, чтобы реализовать однонаправленную ассоциацию «один ко многим», мы можем определить наши сущности как таковые:
Project
организация:
@Entity
public class Project {
@Id
@GeneratedValue
private Long pid;
private String name;
@JoinTable
@OneToMany
private List<Task> tasks;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
}
Task
организация:
@Entity
public class Task {
@Id
@GeneratedValue
private Long tid;
private String name;
public Long getTid() {
return tid;
}
public void setTid(Long tid) {
this.tid = tid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Это создаст следующую структуру базы данных:
@JoinTable
Аннотаций также позволяет настраивать различные аспекты присоединения таблицы. Например, если бы мы аннотировали tasks
свойство следующим образом:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
Получившаяся база данных стала бы:
Наконец, если вы хотите создать схему для ассоциации «многие ко многим», использование таблицы соединений - единственное доступное решение.
@JoinTable/@JoinColumn
можно аннотировать в том же поле с mappedBy
. Таким образом, правильный пример должен быть сохраняя mappedBy
ин Project
, и переместить @JoinColumn
к Task.project
(или наоборот)
Project_Tasks
нуждается name
в Task
а, которая становится три колонки: project_id
, task_id
, task_name
, как добиться этого?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Также проще использовать, @JoinTable
когда Entity может быть дочерним элементом в нескольких родительских / дочерних отношениях с разными типами родителей. Чтобы продолжить пример Бехранга, представьте, что задача может быть дочерним элементом Project, Person, Department, Study и Process.
Должна ли task
таблица иметь 5 nullable
полей внешнего ключа? Думаю, нет...
Это единственное решение для сопоставления ассоциации ManyToMany: вам нужна таблица соединений между двумя таблицами сущностей для сопоставления ассоциации.
Он также используется для OneToMany (обычно однонаправленных) ассоциаций, когда вы не хотите добавлять внешний ключ в таблицу со стороны «многие» и, таким образом, сохранять его независимым от одной стороны.
Найдите @JoinTable в документации по спящему режиму, чтобы найти объяснения и примеры.
Это позволяет вам управлять отношениями "многие ко многим". Пример:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Join Table позволяет создавать сопоставление, используя:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
создаст таблицу:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
ассоциацииЧаще всего вам нужно будет использовать @JoinTable
аннотацию, чтобы указать отображение связи таблицы многие-ко-многим:
Итак, если у вас есть следующие таблицы базы данных:
В Post
сущности вы должны сопоставить это отношение, например:
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
@JoinTable
Аннотаций используется для указания имени таблицы с помощью name
атрибута, а также столбца Внешнего ключа, ссылается на post
таблице (например, joinColumns
) и столбец внешнего ключа в post_tag
таблице ссылок , что ссылается на Tag
объектном через inverseJoinColumns
атрибут.
Обратите внимание, что для атрибута каскад
@ManyToMany
аннотации установлено значениеPERSIST
иMERGE
только потому, что каскадированиеREMOVE
- плохая идея, так как оператор DELETE будет выдан для другой родительской записи,tag
в нашем случае, а не дляpost_tag
записи. Подробнее об этой теме читайте в этой статье .
@OneToMany
ассоциацииОднонаправленные @OneToMany
ассоциации, в которых отсутствует @JoinColumn
отображение, ведут себя как отношения таблиц «многие-ко-многим», а не «один ко многим».
Итак, если у вас есть следующие сопоставления сущностей:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
//Constructors, getters and setters removed for brevity
}
@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {
@Id
@GeneratedValue
private Long id;
private String review;
//Constructors, getters and setters removed for brevity
}
Hibernate будет использовать следующую схему базы данных для указанного выше сопоставления сущностей:
Как уже объяснялось, однонаправленное @OneToMany
сопоставление JPA ведет себя как ассоциация «многие ко многим».
Для настройки таблицы ссылок вы также можете использовать @JoinTable
аннотацию:
@OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JoinTable(
name = "post_comment_ref",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "post_comment_id")
)
private List<PostComment> comments = new ArrayList<>();
И теперь будет вызвана таблица ссылок, post_comment_ref
и столбцы внешнего ключа будут post_id
для post
таблицы и post_comment_id
для post_comment
таблицы.
Однонаправленные
@OneToMany
ассоциации неэффективны, поэтому лучше использовать двунаправленные@OneToMany
ассоциации или только@ManyToOne
боковые. Прочтите эту статью, чтобы узнать больше об этой теме.