Java 删除自引用实体的非级联

Java 删除自引用实体的非级联,java,hibernate,recursion,cascading-deletes,Java,Hibernate,Recursion,Cascading Deletes,我有以下(简化的)Hibernate实体: @Entity @Table(name = "package") public class Package { protected Content content; @OneToOne(cascade = {javax.persistence.CascadeType.ALL}) @JoinColumn(name = "content_id") @Fetch(value = FetchMode.JOIN) pub

我有以下(简化的)Hibernate实体:

@Entity
@Table(name = "package")
public class Package {
    protected Content content;

    @OneToOne(cascade = {javax.persistence.CascadeType.ALL})
    @JoinColumn(name = "content_id")
    @Fetch(value = FetchMode.JOIN)
    public Content getContent() {
        return content;
    }

    public void setContent(Content content) {
        this.content = content;
    }

}


@Entity
@Table(name = "content")
public class Content {
    private Set<Content> subContents = new HashSet<Content>();
    private ArchivalInformationPackage parentPackage;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "subcontents", joinColumns = {@JoinColumn(name = "content_id")}, inverseJoinColumns = {@JoinColumn(name = "elt")})
    @Cascade(value = {org.hibernate.annotations.CascadeType.DELETE, org.hibernate.annotations.CascadeType.REPLICATE})
    @Fetch(value = FetchMode.SUBSELECT)
    public Set<Content> getSubContents() {
        return subContents;
    }

    public void setSubContents(Set<Content> subContents) {
        this.subContents = subContents;
    }

    @ManyToOne(cascade = {CascadeType.ALL})
    @JoinColumn(name = "parent_package_id")
    public Package getParentPackage() {
        return parentPackage;
    }

    public void setParentPackage(Package parentPackage) {
        this.parentPackage = parentPackage;
    }

}
@实体
@表(name=“package”)
公共类包{
受保护的内容;
@OneToOne(cascade={javax.persistence.CascadeType.ALL})
@JoinColumn(name=“content\u id”)
@Fetch(value=FetchMode.JOIN)
公共内容getContent(){
返回内容;
}
公共内容(内容){
this.content=内容;
}
}
@实体
@表(name=“content”)
公开课内容{
private Set subContents=new HashSet();
私有归档信息包parentPackage;
@OneToMany(fetch=FetchType.EAGER)
@JoinTable(name=“subcontents”,joinColumns={@JoinColumn(name=“content\u id”)},inverseJoinColumns={@JoinColumn(name=“elt”)})
@级联(值={org.hibernate.annotations.CascadeType.DELETE,org.hibernate.annotations.CascadeType.REPLICATE})
@Fetch(值=FetchMode.SUBSELECT)
公共集合getSubContents(){
退回分包合同;
}
公共作废集合子目录(集合子目录){
this.subContents=分包商;
}
@manytone(cascade={CascadeType.ALL})
@JoinColumn(name=“parent\u package\u id”)
公共包getParentPackage(){
退货包装;
}
公共无效setParentPackage(包parentPackage){
this.parentPackage=parentPackage;
}
}
所以有一个包,它有一个“顶级”内容。顶部内容链接回包,cascade设置为ALL。顶部内容可能有许多“子”内容,每个子内容可能有自己的许多子内容。每个子内容都有一个父包,它可能与顶部内容是同一个包,也可能不是同一个包(即内容与包之间的多对一关系)

这些关系需要是ManyToOne(包到内容)和ManyToMany(内容到子内容),但对于这种情况,我目前正在测试的每个子内容仅与一个包或内容相关

问题是,当我删除一个包并刷新会话时,我会收到一个Hibernate错误,指出我违反了表
子组件
上的外键约束,并且特定的
内容id仍然引用自表
子组件

在删除包之前,我已经尝试过专门(递归地)删除内容,但是我得到了相同的错误

是否存在未正确删除此实体树的原因

编辑:阅读答案/评论后,我意识到内容不能有多个包,子内容不能有多个父内容,因此我将注释从manytone和ManyToMany修改为OneToOne和OneToMany。不幸的是,这并没有解决问题


我还添加了从内容到父包的双向链接,这是我在简化代码中遗漏的。

如果我理解正确,基于多通映射,一个内容有多个包,我假设您在上面的简化代码中从内容类中删除了“包”集合字段

那么,对于“packages”集合字段,是否有一个级联删除(就像您在分包中所做的那样)?如果你这样做,那么我认为它应该起作用。当您删除根内容时,它应该对每个子内容执行级联删除,然后每个内容将对包执行级联删除


这行得通吗?

问题原来是因为我在删除每个包后刷新和清除会话,并且由于模型中的循环依赖关系,没有删除所有内容。由于涉及非常大的数据集,因此需要刷新和清除。最后,我对其进行了更改,从而构造了一组依赖于当前包的所有实体(可能包括其他包),然后在调用flush和clear之前删除了所有实体。

是包和内容之间的双向关系(代码没有显示这一点,但在阅读描述后我有疑问)是的,这种关系是双向的,我不应该在简化的代码中遗漏它。嗯。。。软件包和内容之间的基数仍然不一致:)是OneToOne还是OneToMany(您当前从一个内容到另一个软件包有多个OneOne)?问题是,我们希望软件包有一个单独的“顶部”内容,从软件包中的字段引用,但也允许“sub”要链接回与顶部内容链接的包相同的包的内容。因此,包与顶部内容之间的关系是一对一,而包与所有内容(顶部内容加上子内容)之间的关系是一对一。这会导致问题吗?如果是这样的话,我应该如何对它进行不同的建模呢?读了这篇文章后,我对它进行了更多的思考,并意识到它真的不应该是一个多人的关系,所以我将它修改为一人一人的关系。我仍然得到相同的错误,我想这是有道理的,因为数据库中没有反映多人关系的数据。我已经更新了包和内容之间关系的摘要。因此,对于包到“顶部”的内容来说是一个选项,但是对于返回到包的内容来说是多个选项(因为顶部和子内容可能共享同一个包)。这种差异会导致问题吗?