Trong trường hợp nào bạn sử dụng @JoinTablechú thích JPA ?
Trong trường hợp nào bạn sử dụng @JoinTablechú 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, JoinTableví dụ này không cần mappedBythuộ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 Projectvà một thực thể khác được đặt tên Taskvà 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 Projectvà một bảng khác được đặt tên Taskvà 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_Tasksvà 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_Tasksbả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 @JoinTablechú 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 @JoinTablechú 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 taskstà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/@JoinColumncó 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ữ mappedBytrong Project, và di chuyển @JoinColumnđến Task.project (hoặc ngược lại)
Project_Taskscần namecủa Tasklà 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 @JoinTablekhi 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 taskbảng có 5 nullablelĩ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 @JoinTablechú 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 Postthự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 @JoinTablechú thích được sử dụng để chỉ định tên bảng thông qua namethuộc tính, cũng như cột Ngoại chính là tài liệu tham khảo các postbảng (ví dụ joinColumns) và cột Ngoại chính trong post_tagbảng liên kết tài liệu tham khảo các Tagthực thể thông qua các inverseJoinColumnsthuộc tính.
Lưu ý rằng thuộc tính tầng của
@ManyToManychú thích được đặt thànhPERSISTvàMERGEchỉ bởi vì xếp tầngREMOVElà 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,tagtrong trường hợp của chúng ta, không phải chopost_tagbản ghi. Để biết thêm chi tiết về chủ đề này, hãy xem bài viết này .
@OneToManyHiệp hộiCác @OneToManyhiệ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 @JoinTablechú 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_refvà các cột Khóa ngoài sẽ post_id, cho postbảng và post_comment_id, cho post_commentbảng.
Các
@OneToManyhiệp hội đơn hướng không hiệu quả, vì vậy bạn nên sử dụng các@OneToManyhiệp hội hai chiều hoặc chỉ là@ManyToOnephụ. Kiểm tra bài viết này để biết thêm chi tiết về chủ đề này.