Don't change the reference to a collection with cascade="all-delete-orphan"
Asked Answered
T

4

10

I am getting an error:

Don't change the reference to a collection with cascade="all-delete-orphan"

while trying the following operation:

beginTx();
Parent parent = new Parent();
Child child = new Child();
parent.addChild(child);
getSession().save(parent);
commitTx();
closeSession();

beginTx();
//id is the primary key
child.setID(null);
getSession().update(child);
commitTx();
closeSession();

Parent and child are related by one-to-many with cascade = 'all-delete-orphan'.

class Parent {
Set child;
}


<set name="child" table="Child" cascade="all-delete-orphan" inverse="true">
    <key column="FK"></key>
    <one-to-many class="Child"/>
</set>

Any idea why this exception is being thrown? Why is setting null on the primary key causing this exception even though the entity is in detached state ?

Tetroxide answered 20/9, 2013 at 6:56 Comment(4)
against which statement it was thrown? is it at this line child.setID(null);?Arachne
What is childCategory ? and what are you trying to achieve by calling child.setID(null); ?Cryotherapy
@debojit : its occurring because of child.setID(null)Tetroxide
@user2599052, by calling child.setID(null); are you attempting to remove a specific entry in the Child Set ?Cryotherapy
A
10

This exception normally happens if you load an entity having a collection with cascade=all-delete-orphan, and then you remove the reference to the collection.

Don't replace this collection. Always use collection.clear() to remove all the associated child entries so that the orphan-deletion algorithm can detect the changes. And if you want to remove any particular child, you just need to remove it from the collection. Once it is removed from the collection, it will be considered as an orphan and will be deleted.

Arachne answered 20/9, 2013 at 8:22 Comment(7)
But if you look at the snippet, I have no where replaced the collection. I am just setting null on the primary key.Tetroxide
That's why I started my ans with "This exception normally happens".. but why are you setting null on the primary key of the child entity?Arachne
The aim is to make the object transient and not do that by removing from collection.Tetroxide
How would that be possible? I am assuming this.correct me if I am wrong.make the object transient:Hibernate will treat it as a new child and will try to persist it. It is same as adding a new child to the set. You want to make it transient but you don't want to remove it from the set. Its like you want to change the ID of a persistent object.But the definition of primary key says that it is not only unique but also constant throughout the life of the row. Hibernate does not support changing identifier values. This could be reason for this exception.Arachne
By making it null, it should be transient, then Hibernate should assign a new key on insertion. And the transient object has to be added to collection of parent and the entities are detached. This what the above code is attempting to do.Tetroxide
but i am still confused !! Anyways, If you want to add a new child, create and add one. If you want to update an existing one, you just need to update its properties. And if you want to remove one, just remove it from the collection. During commitTx(), changes will be synchronized with DB. I don't see any need of making a persistent object transient and then again adding it back to the collection.Arachne
This exact scenario happened when I tried to copy a child object to another parent. I dont find any other solution other than implement .clone() on my child object (luckily only a few field)Intransigence
G
3

for the exception Don't change the reference to a collection with cascade="all-delete-orphan".you use child.setID(null); change the ID cause the exception.

hibernate use PersistentSet to execute the exception check,so you can do this:

child.setID(null);
parent.child=new HashSet(parent.child)

use HashSet to replace PersistentSet

Galvanic answered 11/7, 2016 at 6:17 Comment(0)
G
2

That's because closing the transaction doesn't close the current session. That means that child is still part of the current session, and Hibernate will still consider it to be the same child, and will try to null out its id on the DB.

If you want to make the child object transient, you should use evict() on it.

Gloat answered 11/11, 2015 at 13:44 Comment(0)
S
0

Another reason you can get this is because EntityManager.detach an object in the entity graph followed by EntityManager.flush (which may occur eventually) in which case since it's detached from the entity graph it will try to create a new one again, but it is in a weird state and if you modify it you would get the following error

Don't change the reference to a collection ...

Saltatorial answered 11/2, 2022 at 7:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.