-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 11 posts ] 
Author Message
 Post subject: Deleting Orphans
PostPosted: Mon Jul 31, 2006 3:54 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
I have tried reading the documentation and also the posts on the user forum but i havent read an issue similar to mine.
To put it simply all I want to know is that does something similar to "delete-orphan" construct of "one-to-many" relationships exists for a single reference (mapped by many-to-one).
I cannot map the properties as one-to-one since I need to have their own idfentifier, and secondly for FK not found i am ok with catching an exception or ignoring it. But for certain containment relationships I would want to delete the orphaned object from teh database. So for collections I saw a construct from Hibernate but I couldnt find any solution for a non-collection property.

for example object EmailAccount has a non-collection, contained reference to object AddressBook.
Now a user can manipulate EmailAccount's addressBook property and either make it null or point to a different Addressbook object. Now when such a thing happen it implies that the original value for the addressBook property is orphaned and hence I would want it to get deleted from the database. Just as removing an object from the collection makes it orphaned and it is automatically deleted by Hibernate from the DB.

Hibernate version:
3.0.5

Mapping Excerpt:

<joined-subclass name="EmailAccountImpl" table="TEmailAccount1072563749" batch-size="10">
<key column="PK_persistentIdentifier"/>
<many-to-one not-found="exception" name="addressBook" class="AddressBookImpl" column="FK_addressBook3_AddressBook0" not-null="true" cascade="save-update" lazy="proxy" fetch="select" access="com.informatica.persistence.ormappinggenerator.SinglePropertyAccessor"/>
</joined-subclass>

I would really appreciate any help on this.

Thanks in Advance!!!!!!!

One of teh issues on Jira had something to with delete-orphan wrt to many-to-one relationships. http://opensource.atlassian.com/project ... wse/HBX-81
Which read:
'To solve this issue I made a new annotation "org.hibernate.annotations.OrphanDelete", later in the binding process when OneToMany or ManyToOne is found I check for the existence of OrphanDelete annotation and then pass the info to the method "AnnotationBinder.getCascadeStrategy" '
This gave me hope that dlete-orphan could be used for mnay-to-one relationships in non-ejb persistence too. I tried using it and I did not get any mapping failures but the orphaned object did not get deleted.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 31, 2006 7:53 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
No, there's no orphan delete for the one side of a many-to-one. The best you can do is to execute a separate query for such orphaned entities, and delete them if they exist.

There (probably) never will be an hibernate solution for this, because it doesn't fit into an ORM-style cascade. To do this operation, you need to know about every other object that might refer to the potentially-orphaned entity. That's easy enough in a pure relational environment ("select count(*) from OneSideTable where id = :id") but not so easy when you're dealing with objects ("from Many where OneId = :id", which obviously could load many entities).

Plus, it's a fairly rare case. Most many-to-one assoications are either the inverse of a one-to-many (so the one side will be the parent, and you won't want to delete it just because it has no children), or refer to a "type" entity (a lookup or reference table), where types are static and you'll never want an orphan-delete operation.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 01, 2006 2:12 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
Thanks a lot for the prompt reply. I really appreciate it.

Quote:
There (probably) never will be an hibernate solution for this, because it doesn't fit into an ORM-style cascade. To do this operation, you need to know about every other object that might refer to the potentially-orphaned entity.


So my case was that an object has a parent-child (containment) relationship with another object. But the child object can be referred by other objects (associations). And only if its detached from its parent relation-ship it needs to eb deleted. And for all other objects referring to it, its absolutely fine to have FK not found exceptions.
Its very similar to collection parent-children relationship. A child from the collection might be having other objects referring to it. And once it becomes orphaned(removed from the collection) it is deleted from the DB. And I dont believe that any other objects refering to this deleted object are updated. So if any object was refering to it there would be no row coressponding to teh FK it is holding.
My point is that why a contained collection be any different from a non-collection property.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 01, 2006 5:53 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The difference is that cascading a delete from the many side to the one side may result in a constraint violation exception (assuming that you have real FKs set up). In your case, you won't have that FK at the DB level, as you don't mind having an ID in a row of the many table point to nothing in the one table, but that is a very, very rare situation. Most people would have a proper FK relationship that would prevent that from happening.

Seeing as you don't care that the association can be broken, just unconditionally delete the one side, and set up the many-to-one with not-found="ignore".

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 02, 2006 2:28 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
I am sorry but I dont think i followed your solution.

So the thing I am trying to avoid is explicitly delete the the one side. my many side is no longer pointing to the one side hence the one-side has become orphaned, and this happens on the third tier so the request i get from the third tier no longer passes me any reference to the original one-side object, but passes me the many-side object with a new/another one-side object attached.
I was hoping that just like for collections I get the 'delete-orphan' functionality from Hibernate I could get something similar for non-collection properties too. After all an orphan in cases of non-collection property is just a degenerate case of an orphan from a collection property.
So now the only solution it seems I would have is that before submitting this object to hibernate I query the existing object in DB compare the state of the two objects and then if required explicitly delete the object from the database. Or may be use some event/interceptor to do this.
But this is not good for performance as I do not want to query every object from db before persisting its updated state.
BTW "delete-orphan" works fine for many-to-many relationships too. And to me it just seems that this construct is implementation based as for collections Hibernate uses 'snapshot' to do the operation but for single valued properties it doesnt has any such thing and hence cannot delete the orphan. So I do-not see any logical reason that why a single-valued property doesnt doesnt fall into the ORM-cascading style but collectionns do.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 02, 2006 4:28 pm 
Beginner
Beginner

Joined: Mon Aug 02, 2004 1:08 pm
Posts: 42
Hi Ranjee,

I have the same issue right now for both many-to-one and many-to-many associations and I don't think delete-orphan is a way to solve this in any case. delete-orphan may delete entities which were just removed from the collection, but it does not consider de-associated entities with no references on them.

Assume we have m:m A:B and m:1 C:B.
What I want (and you probably also) is that when I delete A, all Bs which are referenced neither from As nor from Cs are deleted as well.

I don't think Hibernate can do it. It requires testing all potential references to B.

I currently have to ideas for a solution.
The first is a dirty trick that we can actually try deleting B and if we get an constraint violation exception, just ignore it (oops, someone references the object) and don't do further cascades.

The second idea is to analyze hibernate mapping metadata to detect all possible references for each of the mapped classes. Then, implement a time-scheduled task which first detects all unreferenced objects and then removes them. In my case, I can just let the database cleared once a day.

Do you see any other options?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 02, 2006 5:16 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
Thanks for your input Lexi.

But i think my problem is not de-associated objects. In my application its legal that some objects can exist on their own without having any references to them.

But for certain containment relationships like Parent-Child (NOT children) relationship if a parent has changed its child's value to a new object than I want to remove the old child from the database. But I no longer have reference to the old child object through the parent and I do not want that the users of my application have to explicilty delete the child object.
Hence the only solution I see is that before persisting the updated state of the parent object back to the DB I retrieve the parent object from thedatabase, do a diff on the updated parent object and the one retrieved from the DB and depending on teh diff results delete the child object from the database.
I perfectly understand its not reasonable to find all the rows that might be refering to this row and update them all. You can say that apart from teh parent-child relationship any other association is secondary and even if there is a FK violation that fine, my application would deal with it.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 02, 2006 5:39 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Your solution is correct, ranjee. You do have to load the original version of the many-side object if you want to delete the one-side object in this case. delete-orphan can never help in this situation, as there's no way to find out if something is an orphan without doing an additional query. For the one-to-many case (parent-child), nothing on the many side can be referred to except by that single one-side entity. For many-to-one (you called that a parent-child relationship, but it's not: it's a normal association), any number of other entities might refer to the one-side entity that you're thinking might be an orphan.

This sentence makes me think that a design change might help you:
ranjee29 wrote:
But for certain containment relationships like Parent-Child (NOT children) relationship if a parent has changed its child's value to a new object than I want to remove the old child from the database. But I no longer have reference to the old child object through the parent and I do not want that the users of my application have to explicilty delete the child object.

This suggests to me that the one-side of your relationship can refer only to a single many-side entity. Therefore this is not a many-to-one, it's a one-to-one or one-to-many. If this is correct, then I suggest changing that many-to-one to be a <set><one-to-many>, as that is conceptually closer to the data model, and allows delete-orphan. You'd have to add business logic to prevent more than one entity in the set. The only downside is that you'll have to implement an extra method in EmailAccountImpl, because there a mapped set (AddressBooks), but no mapped AddressBook, like there is in your original mapping:
Code:
public AddressBook getAddressBook()
{
   return getAddressBooks().get(0);
}

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 02, 2006 7:48 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
Ok, so in my model it is a 1 to 1 containment between EmailAccountImpl and AddressBookImpl. And it definitely is not a collection property.
Now I cannot map it using one-to-one tag as this implies that my child obkect (AddressBookImpl) will not have its own identifier. Hence as described in the latest Hibernate documentation under section 5.1.11. one-to-one http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#mapping-declaration-onetoone
I am mapping this property using the alternate strategy of using many-to-one tag.
And in my model this is the composit relationship and potentially other objects can have associations to teh AddressBookImpl object that is contained in the EmailAccointImpl object but the same instance on AddressBookImpl object cannot be contained in more than one object instances, but it can definitely be referred by other object instances.
Simply put the AddressBookImpl objects cannot exist on their own, they have to be contained in an instance of EmailAccount but they can be referred outside the EmailAccountObject.
I understand that there is no solution apart from executing an extra select but since Hibernate has a very rich metamodel of teh objects it would be easier for Hibernate to get the exact object from DB for whose property "delete-orphan" cascade has been specified.
I am sorry but I feel that implementing my single valued references as collections with a restricted size of 1 is a very ugly solution.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 09, 2006 1:55 pm 
Newbie

Joined: Wed Jul 26, 2006 9:53 pm
Posts: 16
I am still waiting for a reply....


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 09, 2006 6:16 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Reply? To what? You haven't asked a question. You've expressed disappointment that the easiest way to get hibernate to automatically delete something in this situation is to map it as a collection of one item. There are alternatives that you have already explained. You have all the answers, you just need to pick which one suits you best.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 11 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.