我有以下(简化的)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;
}
}
所以有一个包,其中有一个“顶级”内容。顶级内容链接回包,级联设置为ALL。顶部内容可以具有许多“子”内容,并且每个子内容可以具有其自己的许多子内容。每个子内容都有一个父包,它可能与顶级内容相同也可能不是相同的包(即内容到包的多对一关系)。
关系必须是ManyToOne(包到内容)和ManyToMany(内容到子内容),但对于我目前正在测试每个子内容的情况,只涉及一个包或内容。
问题是,当我删除一个包并刷新会话时,我收到一个Hibernate错误,指出我违反了表subcontents
上的外键约束,并且仍然引用了特定的content_id
来自表subcontents
。
我在删除包之前已经特意(递归地)删除了内容,但是我得到了同样的错误。
是否有理由不正确删除此实体树?
编辑:在阅读答案/评论后,我意识到内容不能有多个包,子内容不能有多个父内容,所以我修改了ManyToOne和ManyToMany的注释OneToOne和OneToMany。不幸的是,这并没有解决问题。
我还将内容中的双向链接添加回了我从简化代码中遗漏的父包。
答案 0 :(得分:1)
如果我理解正确,基于ManyToOne映射,一个内容有很多包,我假设您在上面的简化代码中从Content类中删除了“packages”集合字段?
那么,对于你的“包”收集字段,你是否有一个级联删除(就像你在你的子内容上有的那样)?如果你这样做,那么我认为它应该有效。当您删除根内容时,它应该对每个子内容执行级联删除,然后每个内容将在包上执行级联删除。
这有用吗?
答案 1 :(得分:0)
问题原因是由于我在删除每个包后刷新并清除会话这一事实,并且由于模型中的循环依赖性而不是所有内容都被删除。需要刷新和清除,因为涉及非常大的数据集。最后我更改了它,以便构造一组依赖于当前Package的所有实体(可能包括其他包),然后在调用flush和clear之前删除所有实体。