У якому випадку ви використовуєте @JoinTable
анотацію JPA ?
У якому випадку ви використовуєте @JoinTable
анотацію JPA ?
Відповіді:
EDIT 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
коли суб'єктом господарювання може бути дитина у кількох стосунках батьків / дитини з різними типами батьків. Щоб продовжити приклад Бехранга, уявіть, що завдання може бути дочірнім проекту, персоналу, відділу, навчання та процесу.
Чи має 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 |
|_________|_________|
| | |
|_________|_________|
Таблиця приєднання дозволяє створювати відображення за допомогою:
@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
стороною. Перегляньте цю статтю, щоб дізнатися більше про цю тему.