删除非级联的自引用实体
我有以下(简化的)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;
}
}
因此有一个包,其中有一个“顶级”内容。顶部内容链接回包,级联设置为全部。顶部内容可以具有许多“子”内容,并且每个子内容可以具有其自己的许多子内容。每个子内容都有一个父包,它可能是也可能不是与顶级内容相同的包(即内容与包的多对一关系)。
关系必须是 ManyToOne(包到内容)和 ManyToMany(内容到子内容),但对于我当前测试的情况,每个子内容仅与一个包或内容相关。
问题是当我删除一个包并刷新会话时,我收到一个 Hibernate 错误,指出我违反了表 subcontents
上的外键约束,并且特定的 content_id
仍然存在从表 subcontents
引用。
我已尝试在删除包之前专门(递归地)删除内容,但出现相同的错误。
是否有原因导致该实体树没有被正确删除?
编辑:阅读答案/评论后,我意识到一个内容不能有多个包,一个子内容不能有多个父内容,所以我将注释从ManyToOne和ManyToMany修改为OneToOne和OneToMany 。不幸的是,这并没有解决问题。
我还添加了从内容到父包的双向链接,我将其排除在简化代码之外。
I have the following (simplified) Hibernate entities:
@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;
}
}
So there is one Package, which has one "top" Content. The top Content links back to the Package, with cascade set to ALL. The top Content may have many "sub" Contents, and each sub-Content may have many sub-Contents of its own. Each sub-Content has a parent Package, which may or may not be the same Package as the top Content (ie a many-to-one relationship for Content to Package).
The relationships are required to be ManyToOne (Package to Content) and ManyToMany (Content to sub-Contents) but for the case I am currently testing each sub-Content only relates to one Package or Content.
The problem is that when I delete a Package and flush the session, I get a Hibernate error stating that I'm violating a foreign key constraint on table subcontents
, with a particular content_id
still referenced from table subcontents
.
I've tried specifically (recursively) deleting the Contents before deleting the Package but I get the same error.
Is there a reason why this entity tree is not being deleted properly?
EDIT: After reading answers/comments I realised that a Content cannot have multiple Packages, and a sub-Content cannot have multiple parent-Contents, so I have modified the annotations from ManyToOne and ManyToMany to OneToOne and OneToMany. Unfortunately that did not fix the problem.
I have also added the bi-directional link from Content back to the parent Package which I left out of the simplified code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
事实证明,问题是由于我在删除每个包后刷新并清除会话而引起的,并且由于模型中的循环依赖关系,并非所有内容都被删除。因为涉及非常大的数据集,所以需要刷新和清除。最后我更改了它,以便构造一组依赖于当前包的所有实体(可能包括其他包),然后在调用flush和clear之前将其全部删除。
The problem turned out to be caused by the fact that I was flushing and clearing the session after deleting each Package, and due to the circular dependencies in the model not everything was being deleted. The flush and clear are required because very large data sets are involved. In the end I changed it so that a set of all entities dependent on the current Package is constructed (which may include other Packages) and then all deleted before calling flush and clear.
如果我理解正确的话,根据 ManyToOne 映射,一个 Content 具有多个 Packages,并且我假设您在上面的简化代码中从 Content 类中删除了“packages”集合字段?
那么,对于您的“包”集合字段,您是否有级联删除(就像您的子内容一样)?如果你这样做,那么我认为它应该有效。当你删除根Content时,应该对每个子内容进行级联删除,每个内容再对包进行级联删除。
那有用吗?
If I understand correctly, based on the ManyToOne mapping, one Content has many Packages, and I assume you removed the "packages" collection field from your Content class in your simplified code above?
So, for your "packages" collection field, do you have a cascade delete on it (just like what you have on your subcontents)? If you do, then I think it should work. When you delete the root Content, it should perform cascade delete on each subcontent, and each content will then perform cascade delete on the package.
Does that work?