一对多的单向关联
关系数据库模型中的双向关系是什么?让我们快速看一下 -
假设您有两个表 Post 和 Post_Comment。现在您想找出哪些评论与哪个帖子相关联,或者对于一个帖子,有多少条评论与之相关联?您该怎么做?
以下是基本 Post 实体表
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String title;
public Post() {
}
// ignoring setter and getter
}以下是基本的帖子评论实体表
@Entity
public class PostComment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column
private String description;
public PostComment() {
}
// ignoring setter and getter目前,Post 和 PostComment 实体之间没有任何关系。现在让我们在它们之间建立单向关系。
**需要考虑的关键案例:**
以所有者身份发帖(一对多):
这意味着 Post 实体将管理关系。每个 Post 可以有多个 PostComment 条目。
作为所有者发布评论(多对一):
这里,PostComment 实体将管理关系。每条评论将链接到单个帖子。
让我们从实现案例 1:以所有者身份发帖开始。
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String title;
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
private List postComments = new ArrayList<>();
public Post() {
}
public void addComment(PostComment comment) {
postComments.add(comment);
}
public void removeComment(PostComment comment) {
postComments.remove(comment);
}
// ignoring setter and getter
} 现在我们在这里做了什么?
我们添加了一个列表,并使用 `@OneToMany` 告诉 Post 它可以有零个、一个或多个帖子评论。单个 Post 可以有多条评论。我们在后面的两处中设置了 `cascade = CascadeType.PERSIST, orphanRemoval = true`。
`@OneToMany(级联 = CascadeType.PERSIST,orphanRemoval = true)
私人列表postComments = new ArrayList<>();`
我们还添加了两种方法,可以让我们更轻松地添加/删除评论
public void addComment(PostComment comment) {
postComments.add(comment);
}
public void removeComment(PostComment comment) {
postComments.remove(comment);
}好的,我们几乎完成了实体设计(尚未完全完成)。让我们看看如何保存/保留带有评论的帖子。
@Service
public class PostService {
@Autowired
EntityManager eManager;
@Transactional
public void addPost1() {
Post post = new Post();
post.setTitle("Hibernate in action is quite good");
PostComment comment = new PostComment();
comment.setDescription("Recommended");
post.addComment(comment);
eManager.persist(post);
}
}这里我们创建了一篇文章,然后设置标题并添加评论。然后调用“eManager.persist(post)”,这将保存该文章及其相关评论。很简单,对吧!!!让我们看一下数据库(H2):
我们可以看到 Post 表只有一行,其 id 和 title 均为 1,title 为“Hibernate in action is quite good”。
现在让我们看一下帖子评论表:
我们有一行 id 为 1,描述为推荐。太棒了!但是 POST_POST_COMMENTS 表是什么?我们没有在代码库中明确定义它。
解释如下:
当我们在帖子和评论之间建立一对多关系时,每条评论都会使用 post_id 链接到帖子。这会在 post_id 和 post_comment_id 之间创建映射。但这个映射存储在哪里?
Hibernate 会自动创建一个连接表,将两个实体/表的名称(POST 和 POST_COMMENTS)组合在一起。该表包含两列:
Post 表的主键 (POST_ID)。
Post_Comments 表中的主键 (POST_COMMENT_ID)。
通过这种方式,Hibernate 管理关系而不需要我们在代码中明确定义此表。
我们可以改进吗?额外的桌子会造成额外的负担。是的,我们可以。让我们看看我们如何做到这一点?
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true) @JoinColumn(name = "post_id") private ListpostComments = new ArrayList<>();
`@JoinColumn(name = "post_id")` 此连接列注释告诉我们,我们不需要任何额外的表来进行映射。相反,POST_COMMENT 表将处理它。POST_COMMENT 表中将有一个名为“post_id”的额外列,它将存储该评论的关联帖子 ID,但好消息是 JPA/hibernate 会自行执行此操作。我们不需要更改我们的帖子评论实体。
让我们在 ID 为 1 的帖子中添加另一条评论。
@Transactional
public void addCommentOnPost() {
Post post = eManager.find(Post.class, 1);
PostComment comment = new PostComment();
comment.setDescription("this book is also for beginner");
post.addComment(comment);
eManager.persist(post);
}现在让我们尝试获取这些评论。
@Transactional
public void findCommentByPostId() {
Post post = eManager.find(Post.class, 1);
System.out.println("Number of comment " + post.getPostComments().size());
System.out.println(post.getPostComments());
}
/*
Number of comment 2
[
PostComment [id=1, description=Recommended],
PostComment [id=2, description=this book is also for beginner]
]
*/**JPA/Hibernate 如何获取评论:**
当您调用 post.getPostComments() 时,JPA/Hibernate 会查询 POST_COMMENT 表。它会检查 post_id 列中是否有与 post_id 匹配的条目(在我们的例子中,post_id=1)。然后它会检索所有匹配的行并将它们映射到 PostComment 对象。这就是获取和返回与帖子相关的两条评论的方式
**orphanRemoval = true**
这确保如果从 postComments 列表中删除 PostComment,它将自动从数据库中删除。本质上:
Post post = entityManager.find(Post.class, 1); PostComment comment = post.getPostComments().get(0); post.getPostComments().remove(comment);
如果未设置 orphanRemoval = true,那么即使从列表中删除 PostComment,它仍会存在于数据库中,从而可能导致出现孤立行。
**CascadeType.PERSIST**
这意味着每当您持久化 Post 实体时,所有关联的 PostComment 实体也将自动持久化。换句话说:
Post post = new Post();
PostComment comment = new PostComment();
comment.setDescription("A new comment");
post.getPostComments().add(comment);
entityManager.persist(post);如果没有 CascadeType.PERSIST,您将需要明确保留每个 PostComment