A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

We’re having a bit of trouble with Collections, specifically one of them (out of 3 in this class, hundreds in total including another class that has a collection of the same type of elements).

What advice I’ve found says that great care must be taken not to replace the collection itself, only its elements. It therefore looks like this:

    private List<TypeConstraint> typeConstraints = new ArrayList<>();
    /* ... */
    public void setTypeConstraints(List<TypeConstraint> typeConstraints) {
        this.typeConstraints.clear();
        this.typeConstraints.addAll(typeConstraints);
    }

and is mapped as follows

    <list cascade="all,delete-orphan" lazy="true" name="typeConstraints">
      <key column="CHARGE_ID"/>
      <list-index column="CHARGE_TYPE_POS"/>
      <one-to-many class="se.zaleth.jar.generic.TypeConstraint" not-found="ignore"/>
    </list>

As I said above, it is this collection in this class that generates the exception, not the identical collection in another class. Have we accidentially used a reserved keyword somewhere?

Edit: This is the exception

javax.persistence.PersistenceException: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: se.zaleth.jar.charge.Charge.typeConstraints
	at org.hibernate.bugs.JPAUnitTestCase.hhh123Test(JPAUnitTestCase.java:120)
Caused by: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: se.zaleth.jar.charge.Charge.typeConstraints
	at org.hibernate.bugs.JPAUnitTestCase.hhh123Test(JPAUnitTestCase.java:120)

A test case can be found at this link: orphan-collection.zip - Google Drive

1 Like

I found what’s wrong. Contrary to StackOverflow, I need to replace the collection in the setter … if the new collection is the one Hibernate built while fetching from the database. After replacing my setter with

        if(typeConstraints instanceof PersistentList)
            this.typeConstraints = typeConstraints;
        else {
            this.typeConstraints.clear();
            this.typeConstraints.addAll(typeConstraints);
        }

it all runs smoothly.

1 Like

Hi @zaleth81 ,

public void setTypeConstraints(List<TypeConstraint> typeConstraints) {
        this.typeConstraints = typeConstraints
    }

it is enough;

Hi @dreab8
If I only use

public void setTypeConstraints(List<TypeConstraint> typeConstraints) {
        this.typeConstraints = typeConstraints
    }

I got the error “javax.persistence.PersistenceException: org.hibernate.HibernateException: A collection with cascade=“all-delete-orphan” was no longer referenced by the owning entity instance”, When I set a LinkedHashSet instance to the PersistanceSet instance property getting from database.

Is this behave changed in new hibernate version? I’m using version 5.4.

Sorry for my poor english:)

Properties annotated as -

    @OneToMany(mappedBy = "<some-field>", cascade = CascadeType.ALL, orphanRemoval = true)
    @LazyCollection(LazyCollectionOption.FALSE)
    @OrderBy("id asc")

must not be set directly, In my case it was conflicting with the default behaviour of annotations, i.e management entries in collection typically backed by a database table. As mentioned above checking before hand with instanceof operator and if not PersistentList type setting all elements of collections explicitly solved the problem.
I believe, when using cascade=‘all’ and orphanRemoval=true, Hibernate expects that changes to the collection on the owning side are synchronized with changes on the inverse side (the child entities). In other words, if you remove an element from the collection on the owning side, Hibernate expects the reference to be removed from the inverse side as well. However, setting these directly breaks this expectation therefore throws the error, but adding elements through addAll just bypass this check.