Java JPA@OneToMany-集合与列表-使用集合时无法从双向关联中删除一个子实体
如果使用了Java JPA@OneToMany-集合与列表-使用集合时无法从双向关联中删除一个子实体,java,hibernate,jpa,spring-data-jpa,one-to-many,Java,Hibernate,Jpa,Spring Data Jpa,One To Many,如果使用了Set,则无法从OneToMany关联中删除子实体。如果我使用List而不是Set Post.java @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) private List<Comment> comments; public void addComment(Comment comment) { if (comments == null) {
Set
,则无法从OneToMany关联中删除子实体。如果我使用List
而不是Set
Post.java
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
public void addComment(Comment comment) {
if (comments == null) {
comments = new ArrayList<>();
}
comment.setPost(this);
comments.add(comment);
}
public void removeComment(Comment comment) {
if (comments == null || comments.isEmpty()) {
return;
}
comments.remove(comment);
comment.setPost(null);
}
示例应用程序的代码可在
分支正在使用master
,测试用例失败Set
分支正在使用“list”和测试用例通过list
我不确定我是否犯了什么错误。请建议。您的测试根据
帖子评论的大小进行断言。它也是@Transactional
,意思是postRepository.getOne()
返回与持久性上下文中已有的Post
完全相同的实例。这意味着dbPost==post
,因此您的问题与JPA无关,它纯粹是一个Java问题
尝试在注释处放置断点。删除(注释)
行。您可能会看到,对于Set
版本,它返回false
。这是因为没有正确实现hashCode/equals
。尝试使用comments.removeIf(element->element.getId().equals(comment.getId())
来查看问题是否消失
(作为旁注:JPA实体可以通过多种方式实现equals/hashCode
,但根据经验,将其与被引用实体进行比较不是一个好主意,尤其是当被引用实体应该被延迟获取时)
编辑:
代码对列表
有效,而对集
无效的原因是:
列表
根本不使用hashCode
- 查找元素时,
HashSet
使用hashCode
前面的equals
值来确定潜在的相等性
- 更新元素时,已在
HashSet
中的元素的hashCode
不会自动重新计算
在测试中,当您向Post
添加Comment
时,每个注释的hashCode
都是基于Post.id
为null
的
,Post.id
变为非空,并且您试图删除的注释的hashCode
。因此,remove
无法在集中找到与(新计算的)相同(原始)hashCode
的元素hashCode
用于作为参数传递的注释。这是设计的事实,equals
将为其中一个元素返回true
。列表
没有这个问题,因为它用于元素比较的所有内容都是equals
。谢谢您的帮助响应。当我调试该问题时,我确实观察到该问题是由于对象相等性为false造成的。但我不确定当我将Set
替换为List
时,为什么相同的代码会起作用。谈到equals/hashcode
实现,我更愿意只使用@Id
字段。但由于我使用的是UUID标识符,我不确定无法保存包含多条注释的帖子
(在对象被持久化之前,ID保持为null
,因此只保存一条注释)回答得好,我也认为是一样的
@ManyToOne(fetch = FetchType.LAZY)
@EqualsAndHashCode.Include
private Post post;