Trong trường hợp nào bạn sử dụng @JoinTable
chú thích JPA ?
Trong trường hợp nào bạn sử dụng @JoinTable
chú thích JPA ?
Câu trả lời:
EDIT 2017-04-29 : Như được chỉ ra bởi một số người bình luận, JoinTable
ví dụ này không cần mappedBy
thuộc tính chú thích. Trên thực tế, các phiên bản gần đây của Hibernate từ chối khởi động bằng cách in lỗi sau:
org.hibernate.AnnotationException:
Associations marked as mappedBy must not define database mappings
like @JoinTable or @JoinColumn
Hãy giả vờ rằng bạn có một thực thể được đặt tên Project
và một thực thể khác được đặt tên Task
và mỗi dự án có thể có nhiều nhiệm vụ.
Bạn có thể thiết kế lược đồ cơ sở dữ liệu cho kịch bản này theo hai cách.
Giải pháp đầu tiên là tạo một bảng có tên Project
và một bảng khác được đặt tên Task
và thêm một cột khóa ngoại vào bảng tác vụ có tên project_id
:
Project Task
------- ----
id id
name name
project_id
Bằng cách này, sẽ có thể xác định dự án cho mỗi hàng trong bảng nhiệm vụ. Nếu bạn sử dụng phương pháp này, trong các lớp thực thể của bạn, bạn sẽ không cần một bảng tham gia:
@Entity
public class Project {
@OneToMany(mappedBy = "project")
private Collection<Task> tasks;
}
@Entity
public class Task {
@ManyToOne
private Project project;
}
Giải pháp khác là sử dụng bảng thứ ba, ví dụ Project_Tasks
và lưu trữ mối quan hệ giữa các dự án và tác vụ trong bảng đó:
Project Task Project_Tasks
------- ---- -------------
id id project_id
name name task_id
Các Project_Tasks
bảng được gọi là "Tham Bảng". Để thực hiện giải pháp thứ hai này trong JPA, bạn cần sử dụng @JoinTable
chú thích. Ví dụ: để triển khai liên kết một-nhiều-hướng, chúng ta có thể định nghĩa các thực thể của mình như sau:
Project
thực thể:
@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
thực thể:
@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;
}
}
Điều này sẽ tạo ra cấu trúc cơ sở dữ liệu sau:
Các @JoinTable
chú thích cũng cho phép bạn tùy chỉnh các khía cạnh khác nhau của bảng tham gia. Ví dụ: chúng tôi đã chú thích tasks
tài sản như thế này:
@JoinTable(
name = "MY_JT",
joinColumns = @JoinColumn(
name = "PROJ_ID",
referencedColumnName = "PID"
),
inverseJoinColumns = @JoinColumn(
name = "TASK_ID",
referencedColumnName = "TID"
)
)
@OneToMany
private List<Task> tasks;
Cơ sở dữ liệu kết quả sẽ trở thành:
Cuối cùng, nếu bạn muốn tạo một lược đồ cho liên kết nhiều-nhiều, sử dụng bảng tham gia là giải pháp khả dụng duy nhất.
@JoinTable/@JoinColumn
có thể được chú thích trên cùng một lĩnh vực với mappedBy
. Vì vậy, ví dụ chính xác nên được giữ mappedBy
trong Project
, và di chuyển @JoinColumn
đến Task.project
(hoặc ngược lại)
Project_Tasks
cần name
của Task
là tốt, mà sẽ trở thành ba cột: project_id
, task_id
, task_name
, làm thế nào để đạt được điều này?
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn:
Nó cũng sạch hơn @JoinTable
khi sử dụng khi một Thực thể có thể là đứa trẻ trong một số mối quan hệ cha mẹ / con cái với các loại cha mẹ khác nhau. Để theo dõi ví dụ của Behrang, hãy tưởng tượng một Nhiệm vụ có thể là con của Dự án, Người, Bộ phận, Nghiên cứu và Quy trình.
Nên các task
bảng có 5 nullable
lĩnh vực trọng điểm nước ngoài? Tôi nghĩ là không ...
Đó là giải pháp duy nhất để ánh xạ liên kết ManyToMany: bạn cần một bảng nối giữa hai bảng thực thể để ánh xạ liên kết.
Nó cũng được sử dụng cho các hiệp hội OneToMany (thường là một chiều) khi bạn không muốn thêm khóa ngoại vào bảng của nhiều bên và do đó giữ cho nó độc lập với một bên.
Tìm kiếm @JoinTable trong tài liệu ngủ đông để giải thích và ví dụ.
Nó cho phép bạn xử lý nhiều mối quan hệ Nhiều. Thí dụ:
Table 1: post
post has following columns
____________________
| ID | DATE |
|_________|_________|
| | |
|_________|_________|
Table 2: user
user has the following columns:
____________________
| ID |NAME |
|_________|_________|
| | |
|_________|_________|
Tham gia Bảng cho phép bạn tạo ánh xạ bằng cách sử dụng:
@JoinTable(
name="USER_POST",
joinColumns=@JoinColumn(name="USER_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="POST_ID", referencedColumnName="ID"))
sẽ tạo một bảng:
____________________
| USER_ID| POST_ID |
|_________|_________|
| | |
|_________|_________|
@ManyToMany
hiệp hộiThông thường, bạn sẽ cần sử dụng @JoinTable
chú thích để chỉ định ánh xạ của mối quan hệ nhiều-nhiều bảng:
Vì vậy, giả sử bạn có các bảng cơ sở dữ liệu sau:
Trong Post
thực thể, bạn sẽ ánh xạ mối quan hệ này, như thế này:
@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<>();
Các @JoinTable
chú thích được sử dụng để chỉ định tên bảng thông qua name
thuộc tính, cũng như cột Ngoại chính là tài liệu tham khảo các post
bảng (ví dụ joinColumns
) và cột Ngoại chính trong post_tag
bảng liên kết tài liệu tham khảo các Tag
thực thể thông qua các inverseJoinColumns
thuộc tính.
Lưu ý rằng thuộc tính tầng của
@ManyToMany
chú thích được đặt thànhPERSIST
vàMERGE
chỉ bởi vì xếp tầngREMOVE
là một ý tưởng tồi vì chúng ta sẽ phát hành câu lệnh XÓA cho bản ghi cha khác,tag
trong trường hợp của chúng ta, không phải chopost_tag
bản ghi. Để biết thêm chi tiết về chủ đề này, hãy xem bài viết này .
@OneToMany
Hiệp hộiCác @OneToMany
hiệp hội đơn hướng , thiếu một@JoinColumn
ánh xạ, hoạt động giống như các mối quan hệ nhiều-nhiều, thay vì một-nhiều.
Vì vậy, giả sử bạn có ánh xạ thực thể sau:
@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 sẽ giả sử lược đồ cơ sở dữ liệu sau cho ánh xạ thực thể ở trên:
Như đã giải thích, @OneToMany
ánh xạ JPA đơn hướng hoạt động giống như một hiệp hội nhiều-nhiều.
Để tùy chỉnh bảng liên kết, bạn cũng có thể sử dụng @JoinTable
chú thích:
@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<>();
Và bây giờ, bảng liên kết sẽ được gọi post_comment_ref
và các cột Khóa ngoài sẽ post_id
, cho post
bảng và post_comment_id
, cho post_comment
bảng.
Các
@OneToMany
hiệp hội đơn hướng không hiệu quả, vì vậy bạn nên sử dụng các@OneToMany
hiệp hội hai chiều hoặc chỉ là@ManyToOne
phụ. Kiểm tra bài viết này để biết thêm chi tiết về chủ đề này.