Hibernate PersistentSet remove()操作不起作用

时间:2014-08-04 18:28:35

标签: 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;
}

现在事件,如果我对其中一个元素的Set执行了remove()操作,它实际上并没有被删除。

3 个答案:

答案 0 :(得分:7)

您的映射应如下所示:

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

正如this article中所述,因为您有双向关联,所以必须让双方同步。

因此,最好打电话:

parent.removeChild(child);

这样,removeChild将从Child children中移除Set,并将Child parent关联设置为{ {1}}。

答案 1 :(得分:2)

我有同样的问题,虽然使用remove和setParent为null,但相关数据仍然是db。调试后,我看到相关的子对象无法从父母的子列表中删除。当我搜索&#34; hibernate set删除不工作&#34;在网上,我发现了hibernate真相:remove方法有一些bug,因为hashcode和equals方法。在seing之后我认为removeAll()方法可能正常工作。我把相关的一个对象放到列表中并将列表放到removeAll方法中并且它成功了。举个例子:

List childList = new ArrayList();
childList.add(child);
parent.removeAll(childList);
child.setParent(null);

答案 2 :(得分:0)

实际上,对于使用自定义equals()hashCode()的以下情况,根本原因可能也位于其他地方:

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

在这种情况下,HashTable无法删除对象,因为它“在别处看起来”。当然,这不是错误,而只是HashTable的基本原理之一。

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
}

PS:声称这不能回答原始问题在某种程度上是正确的-这不是答案,而是一种解释,并且原始类没有覆盖hashCodeequals-但至少它描述了@ Mustafa-Kemal提到的“解决方法”需求的最可能原因,即使使用@ Vlad-Mihalcea提到的广泛使用的方法,也必须记住这一点。

注1:EntityManager::merge(...)可能会更改(并且通常会更改)对象的内存地址,用于(我不保证)用于hashCode()的默认计算-请参见System.identityHashCode(Object x );有关更多信息。

注2:如果您使用自定义的hashCode方法,EntityManager::persist(...)可能会更改用于hashCode计算的属性-是的,我在说的是主键,一个id,在这里很想用作hashCode :)