views:

171

answers:

2

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.

+1  A: 

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?

limc
After reading this I gave it some more thought and realised that it really shouldn't be a ManyToOne relationship at all so I modified it to be OneToOne. I still get the same error, which I guess makes sense as there was no data in the database reflecting a ManyToOne relationship.I've updated the summary of the relationship between Package and Content.So it's OneToOne for Package to the "top" Content, but ManyToOne for Content back to Package (as the top and sub Contents may share the same Package). Could that discrepancy be causing the problem?
jwaddell
A: 

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.

jwaddell