Issue Details (XML | Word | Printable)

Key: HHH-785
Type: Improvement Improvement
Status: Closed Closed
Resolution: Won't Fix
Priority: Major Major
Assignee: Unassigned
Reporter: Christian Bauer
Votes: 0
Watchers: 3
Operations

If you were logged in you would be able to see more operations.
Hibernate Core

Persistence through cascading should have higher precedence than orphan-delete

Created: 23/Jul/05 03:42 PM   Updated: 15/May/07 03:48 PM   Resolved: 11/Aug/05 05:11 PM
Return to search
Component/s: core
Affects Version/s: 3.1 beta 1
Fix Version/s: None

Time Tracking:
Not Specified

Participants: Aaron Digulla, Christian Bauer, Gavin King, Joe Kelly and Thom Pischke


 Description  « Hide

A typical tree mapped using an adjacency list:

<many-to-one name="parent" cascade="none"/>
<set name="children" cascade="all, delete-orphan"/>

A normal tree operation is moving a node:

a.remove(b);
c.add(b);

This results in an exception, as Hibernate currently rates the delete-orphan as more important and warns that the node would become persistent again through cascading. However, this is the only way to implement relocation of a node in a tree without resorting to complex session coding. I argue that the "delete orphans" guarantee given in the mapping should not have precedence over the the actual non-orphaned persistent state in the Session.



Christian Bauer added a comment - 23/Jul/05 04:03 PM

Actually, my example of "moving" wasn't entirely complete, because I obviously wouldn't need orphan-delete for this enabled at all. The problem is I'd still like to have it for a simple delete of a node.


Gavin King added a comment - 11/Aug/05 05:11 PM

Unfortunately, this would be very, very difficult to implement.


Thom Pischke added a comment - 22/Mar/06 07:29 AM

A pity. I can imagine why this would be very difficult to implement, but it'd be fantastic if Hibernate were someday able to handle moving a child to a new parent without needing to resort to handling deletion of orphans manually. We have many examples in our code where we move a child to a new parent.

In our case, we do a lot of modification of detached entities. When the time comes to save all the changes (User hits 'Save' button), then we start a Session/Transaction and 'update' the model object to reattach it to the Session and write all the changes to disk. These updates include both removal (deletion) of objects, and transferral of objects to new parents.

Since many such changes can accumulate outside the scope of a Session, manual handling of orphan deletion would be very difficult, since we would essentially need to query the database after writing all the changes to manually find all orphaned objects. Not even sure that would be possible, since we would get exceptions if the parent were ever deleted, since the foreign key constraints of the children would be violated. Our workaround for all this is simply to clone the children which need to be moved to new parents, resulting in the original child being deleted, and a new identical child being persisted, but with a different parent. Of course, this is inelegant, inefficient and results in quite an accumulation of clones, since we also have to store 'undo' information for each movement of the child.

Anyway, probably you're sighing and thinking 'What the hell does this guy think he's doing?', but I thought it might be useful to someone if I added our use-case to this issues discussion.


Aaron Digulla added a comment - 11/Jul/06 07:26 AM

Note: In HHH-1894, I have a much more simple case which is inside a transation, using non-detached objects and there, it doesn't work as well.

A pity.


Joe Kelly added a comment - 15/May/07 03:48 PM

I realize this issue is closed but I wanted to put in my two cents. I totally agree with Christian's argument: persistence through cascading should indeed have higher precedence than orphan-delete. As Christian says, without this feature, you must resort to complex session coding to relocate a node.

Christian's code example seems to be the most natural and transparent way to relocate a node, but it doesn't work, of course:
a.remove(b);
c.add(b);
session.flush();

The following code works but seems less natural and transparent, in my opinion:
b.setParent(c);
session.flush();
session.refresh(a);
session.refresh(c);