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);

实际上,使用custom
equals()
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
}