Java Hibernate PersistentSet remove()操作不起作用
我在父实体中有一个集合,如下所示:Java Hibernate PersistentSet remove()操作不起作用,java,hibernate,jpa,set,spring-data-jpa,Java,Hibernate,Jpa,Set,Spring Data Jpa,我在父实体中有一个集合,如下所示: Class Parent { @OneToMany(mappedBy = parent, cascade = CasacadeType.ALL) Set<Child> children; } Class Child { @Column(nullable=false) @ManyToOne Parent parent; } 类父类{ @OneToMany(mappedBy=parent,cascade=CasacadeType.ALL)
Class Parent {
@OneToMany(mappedBy = parent, cascade = CasacadeType.ALL)
Set<Child> children;
}
Class Child {
@Column(nullable=false)
@ManyToOne
Parent parent;
}
类父类{
@OneToMany(mappedBy=parent,cascade=CasacadeType.ALL)
设置儿童;
}
班童{
@列(nullable=false)
@许多酮
父母;
}
如果我对集合中的一个元素执行remove()操作,它实际上不会被删除。您的映射应该如下所示:
public class Parent {
@OneToMany(mappedBy = parent, cascade = CasacadeType.ALL, orphanRemoval = true)
private Set<Child> children = new HashSet<>();
public void removeChild(Child child) {
children.remove(child);
child.setParent(null);
}
}
public class Child {
@ManyToOne
private Parent parent;
}
这样,
removeChild
将从children
集合中删除子项
,并将子项
父项关联设置为null我也遇到了同样的问题,尽管使用remove并将父项设置为null,但相关数据仍处于db状态。调试后,我发现相关的子对象无法从父对象的子对象列表中删除。当我在网上搜索“hibernate set remove not working”时,我发现了hibernate的真相:remove方法有一些bug,因为hashcode和equals方法。在经历了这些之后,我认为removeAll()方法可能会正常工作。我将相关的一个对象放入list,并将list放入removeAll方法,结果成功了。例如:
List childList = new ArrayList();
childList.add(child);
parent.removeAll(childList);
child.setParent(null);
实际上,使用customequals()
和hashCode()
时,以下情况的根本原因也可能在别处:
在这种情况下,哈希表无法删除该对象,因为它“在别处查找”。当然,这不是bug,只是哈希表的基本原理之一
public static void main(String[] args) {
Child child1 = new Child(123);
HashSet<Child> hashSet = new HashSet<>();
hashSet.add(child1); //puts to hash table at position X
child1.setId(321);
hashSet.remove(child1);//looks at position Y
//child1 is still in the set
}
publicstaticvoidmain(字符串[]args){
Child child1=新孩子(123);
HashSet HashSet=新的HashSet();
hashSet.add(child1);//放入位于X位置的哈希表
child1.setId(321);
hashSet.remove(child1);//查看位置Y
//child1仍在片场
}
PS:声称这不回答原始问题将是部分正确的-这不是一个这样的答案,更不是一个解释,原始类不会覆盖hashCode
或equals
——但至少它描述了@Mustafa Kemal提到的需要“变通方法”的最可能原因,即使在使用@Vlad Mihalcea提到的广泛使用的方法时,您也必须记住这一点
注1:EntityManager::merge(…)
可能会更改(并且通常会更改)对象的内存地址,用于(我的部分不保证)hashCode()的默认计算-请参阅System.identityHashCode(对象x);更多信息
注2:EntityManager::persist(…)
如果使用自定义的hashCode方法,可能会更改用于hashCode计算的属性-是的,我在这里谈论的是主键,一个id,它很容易用作hashCode:)表示当集合被急切加载时,Hibernate不支持equals方法。但是这里我使用了延迟加载。我已经更新了这个问题。子对象中的父对象不能为null。如果使用hbmddl,则nullable=false将应用于自动生成的架构。如果使用生成的架构,则可能无法将child.parent设置为null。不幸的是,在急切获取该集时,这不起作用:-仅从版本6开始
public class Child {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Child(int id) {
this.id = id;
}
//other fields
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
//instanceof checks for null, but whatever...
if (obj == null || !(obj instanceof Child)) {
return false;
}
return this.id == ((Child)obj).id;
}
}
public static void main(String[] args) {
Child child1 = new Child(123);
HashSet<Child> hashSet = new HashSet<>();
hashSet.add(child1); //puts to hash table at position X
child1.setId(321);
hashSet.remove(child1);//looks at position Y
//child1 is still in the set
}