Đây là một câu hỏi rất phổ biến, vì vậy câu trả lời này dựa trên bài viết này tôi đã viết trên blog của mình.
Một-nhiều
Mối quan hệ một-nhiều bảng trông như sau:
Trong một hệ thống cơ sở dữ liệu quan hệ, mối quan hệ một-nhiều bảng liên kết hai bảng dựa trên một Foreign Key
cột trong con tham chiếu đến hàng Primary Key
của bảng cha.
Trong sơ đồ bảng ở trên, post_id
cột trong post_comment
bảng có Foreign Key
mối quan hệ với cột post
id bảng Primary Key
:
ALTER TABLE
post_comment
ADD CONSTRAINT
fk_post_comment_post_id
FOREIGN KEY (post_id) REFERENCES post
Chú thích @ManyToOne
Cách tốt nhất để ánh xạ mối quan hệ một-nhiều bảng là sử dụng @ManyToOne
chú thích.
Trong trường hợp của chúng tôi, thực thể con, PostComment
ánh xạ post_id
cột Khóa ngoài bằng cách sử dụng @ManyToOne
chú thích:
@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;
}
Sử dụng @OneToMany
chú thích JPA
Chỉ vì bạn có tùy chọn sử dụng @OneToMany
chú thích, điều đó không có nghĩa đây sẽ là tùy chọn mặc định cho mỗi một-nhiều mối quan hệ cơ sở dữ liệu . Vấn đề với các bộ sưu tập là chúng tôi chỉ có thể sử dụng chúng khi số lượng hồ sơ con khá hạn chế.
Cách tốt nhất để lập bản đồ @OneToMany
liên kết là dựa vào một @ManyToOne
bên để tuyên truyền tất cả các thay đổi trạng thái thực thể:
@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<>();
//Constructors, getters and setters removed for brevity
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void removeComment(PostComment comment) {
comments.remove(comment);
comment.setPost(null);
}
}
Thực thể mẹ Post
, có hai phương thức tiện ích (ví dụ addComment
và removeComment
) được sử dụng để đồng bộ hóa cả hai mặt của liên kết hai chiều. Bạn nên luôn luôn cung cấp các phương thức này bất cứ khi nào bạn làm việc với một hiệp hội hai chiều vì nếu không, bạn có nguy cơ gặp phải các vấn đề lan truyền trạng thái rất tinh tế .
Nên @OneToMany
tránh liên kết đơn hướng vì nó kém hiệu quả hơn so với sử dụng @ManyToOne
hoặc @OneToMany
liên kết hai chiều .
Để biết thêm chi tiết về cách tốt nhất để lập bản đồ @OneToMany
mối quan hệ với JPA và Hibernate, hãy xem bài viết này .
Một chọi một
Mối quan hệ một-một-bảng trông như sau:
Trong một hệ thống cơ sở dữ liệu quan hệ, mối quan hệ một-một liên kết hai bảng dựa trên một Primary Key
cột trong con cũng là Foreign Key
tham chiếu Primary Key
của hàng của bảng cha.
Do đó, chúng ta có thể nói rằng bảng con chia sẻ Primary Key
với bảng cha.
Trong sơ đồ bảng trên, id
cột trong post_details
bảng cũng có Foreign Key
mối quan hệ với cột post
bảng id
Primary Key
:
ALTER TABLE
post_details
ADD CONSTRAINT
fk_post_details_id
FOREIGN KEY (id) REFERENCES post
Sử dụng JPA @OneToOne
với @MapsId
các chú thích
Cách tốt nhất để lập bản đồ @OneToOne
mối quan hệ là sử dụng @MapsId
. Theo cách này, bạn thậm chí không cần liên kết hai chiều vì bạn luôn có thể tìm nạp PostDetails
thực thể bằng cách sử dụng Post
định danh thực thể.
Ánh xạ trông như thế này:
[code ngôn ngữ = "java"] @Entity (name = "PostDetails") @Table (name = "post_details") lớp công khai 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;
}
//Getters and setters omitted for brevity
} [/ mã]
Bằng cách này, id
tài sản đóng vai trò là Khóa chính và Khóa ngoại. Bạn sẽ nhận thấy rằng @Id
cột không còn sử dụng @GeneratedValue
chú thích vì mã định danh được điền với mã định danh của post
liên kết.
Để biết thêm chi tiết về cách tốt nhất để lập bản đồ @OneToOne
mối quan hệ với JPA và Hibernate, hãy xem bài viết này .
Nhiều nhiều
Mối quan hệ nhiều-nhiều-bảng trông như sau:
Trong một hệ thống cơ sở dữ liệu quan hệ, mối quan hệ nhiều-nhiều bảng liên kết hai bảng cha thông qua một bảng con chứa hai Foreign Key
cột tham chiếu các Primary Key
cột của hai bảng cha.
Trong sơ đồ bảng ở trên, post_id
cột trong post_tag
bảng cũng có Foreign Key
mối quan hệ với cột post
id bảng Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_post_id
FOREIGN KEY (post_id) REFERENCES post
Và, tag_id
cột trong post_tag
bảng có Foreign Key
mối quan hệ với cột tag
id bảng Primary Key
:
ALTER TABLE
post_tag
ADD CONSTRAINT
fk_post_tag_tag_id
FOREIGN KEY (tag_id) REFERENCES tag
Sử dụng @ManyToMany
ánh xạ JPA
Đây là cách bạn có thể ánh xạ many-to-many
mối quan hệ bảng với JPA và 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<>();
//Getters and setters ommitted for brevity
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<>();
//Getters and setters ommitted for brevity
@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);
}
}
- Liên
tags
kết trong Post
thực thể chỉ định nghĩa các loại PERSIST
và MERGE
tầng. Như đã giải thích trong bài viết này , REMOVE
quá trình chuyển đổi trạng thái thực thể không có ý nghĩa gì đối với một @ManyToMany
hiệp hội JPA vì nó có thể kích hoạt việc xóa chuỗi mà cuối cùng sẽ xóa sạch cả hai mặt của hiệp hội.
- Như đã giải thích trong bài viết này , các phương thức tiện ích thêm / xóa là bắt buộc nếu bạn sử dụng các liên kết hai chiều để bạn có thể đảm bảo rằng cả hai mặt của liên kết đều đồng bộ.
- Thực
Post
thể sử dụng định danh thực thể cho sự bình đẳng vì nó không có bất kỳ khóa kinh doanh duy nhất nào. Như đã giải thích trong bài viết này , bạn có thể sử dụng định danh thực thể cho sự bình đẳng miễn là bạn đảm bảo rằng nó vẫn nhất quán trong tất cả các chuyển đổi trạng thái thực thể .
- Thực
Tag
thể có khóa doanh nghiệp duy nhất được đánh dấu bằng @NaturalId
chú thích dành riêng cho Hibernate . Khi đó, khóa kinh doanh duy nhất là ứng cử viên tốt nhất để kiểm tra bình đẳng .
- Các
mappedBy
thuộc tính của posts
hiệp hội trong Tag
dấu ngoặc đơn vị rằng, trong mối quan hệ hai chiều này, các Post
đơn vị sở hữu hiệp hội. Điều này là cần thiết vì chỉ một bên có thể sở hữu một mối quan hệ và các thay đổi chỉ được truyền đến cơ sở dữ liệu từ phía cụ thể này.
- Điều
Set
này được ưu tiên, vì sử dụng một List
với @ManyToMany
ít hiệu quả hơn.
Để biết thêm chi tiết về cách tốt nhất để lập bản đồ @ManyToMany
mối quan hệ với JPA và Hibernate, hãy xem bài viết này .