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.  [ 13 posts ] 
Author Message
 Post subject: coll of obj refs: delete obj, how to to remove coll entry ?
PostPosted: Tue Feb 14, 2006 9:15 pm 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
Hibernate version: 3.05



Hi all,

I have a parent/child setup as follows:
Code:
class Parent
{
   Set<Child> children;
}

class Child
{
...
}


Note there is no reference from the child back to the parent
(in this case the 'child' knows nothing about the 'parent' and cannot
and should not be managing the relationship).

What I'd like to achieve is to be able to delete a child, and get
Hibernate to remove the association from the container without
having to do this myself. This is due to the fact that at the point
of deletion, the only available reference is that of the 'child' and
I would like to keep the knowledge of this relationship out of the
code that deletes that child.

Is it possible to do?

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 14, 2006 10:14 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
So long as there are no in-memory instances of the parent, then it happens automatically. If the parent is in memory (even in Hibernate's cache), you'll have to refresh it (session.evict(parent) will do the job, as will session.refresh(parent)).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 2:42 am 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
tenwit,

tenwit wrote:
So long as there are no in-memory instances of the parent, then it happens automatically. If the parent is in memory (even in Hibernate's cache), you'll have to refresh it (session.evict(parent) will do the job, as will session.refresh(parent)).



Sorry, but I do not think I follow - what does this have to do with the
state of the parent?

I thought what I wanted to accomplish should be
independent of the presence of the parent, since, as I mentioned, at
the point of deletion of the child, the parent is unknown, and since there's
no reference from the child to the parent, there is no way to follow
the association (using the child, that is). I thought that Hibernate,
given it's knowledge of the persistence meta model would detect that the
child is being deleted and discover that it is being referred to, using a
unidirectional association, by the 'parent' and automatically delete
the association for me (and if it is possible, then I would like to know
how to express this in the mapping file).

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 4:33 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
That depends on how you've implemented the association in the DB. As it's a unidirectional one-to-many mapping, the most obvious choice would be to have a FK in the child table pointing directly to the parent table. I have assumed that this is the model you've used. When you delete a row from the child table, the parent no longer knows about the child row: the only thing describing the association between the child and parent was the child itself.

If the parent object is in not memory at the time, then nothing more needs to be done. The next time you load the parent, it won't have the child in its set. If the parent object is in memory, then you will have to refresh it from the DB, so that its Set member is reloaded. This is why I suggested using either refresh or evit.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 7:24 pm 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
tenwit wrote:
That depends on how you've implemented the association in the DB. As it's a unidirectional one-to-many mapping, the most obvious choice would be to have a FK in the child table pointing directly to the parent table. I have assumed that this is the model you've used. When you delete a row from the child table, the parent no longer knows about the child row: the only thing describing the association between the child and parent was the child itself.

If the parent object is in not memory at the time, then nothing more needs to be done. The next time you load the parent, it won't have the child in its set. If the parent object is in memory, then you will have to refresh it from the DB, so that its Set member is reloaded. This is why I suggested using either refresh or evit.


OK, I think I understand your suggestion better. However, in my post
I've indicated that the child knows nothing aboutt the parent and in fact
it may be associated with multiple parents. Would it still be possible to
achieve if that were the case?

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 8:41 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I'm speculating here, because you haven't posted your mapping.

If a child may have multiple parents then you've got a many-to-many. So long as deleting the child also deletes the relevant rows in the parent-to-child join table, then the same stuff applies. In fact, it will always apply, the only thing that might change is that deleting the child might fail if it doesn't also delete the rows in the join table. This will be the case if you've set up your mapping without inverse="true" on the parent set mapping, which obviously you must have because otherwise there would be no way to create the rows in that table.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 16, 2006 8:27 pm 
Regular
Regular

Joined: Fri Oct 01, 2004 2:19 am
Posts: 111
Location: Melbourne, Australia
tenwit wrote:
I'm speculating here, because you haven't posted your mapping.

If a child may have multiple parents then you've got a many-to-many. So long as deleting the child also deletes the relevant rows in the parent-to-child join table, then the same stuff applies. In fact, it will always apply, the only thing that might change is that deleting the child might fail if it doesn't also delete the rows in the join table. This will be the case if you've set up your mapping without inverse="true" on the parent set mapping, which obviously you must have because otherwise there would be no way to create the rows in that table.


I have not included the mapping since I was not sure how to go about this.
In the meantime, I experimented a bit and found that given the following
mapping:
Code:
    <class name="events.Parent" table="PARENTS">
        <id name="id" column="PARENT_ID">
            <generator class="native"/>
        </id>

        <property name="name"/>

        <set name="children" table="PARENT_CHILDREN" cascade="save-update">
            <key column="PARENT_ID"/>
            <many-to-many column="CHILD_ID" class="events.Child"/>
        </set>

    </class>

    <class name="events.Child" table="CHILDREN">
        <id name="id" column="CHILD_ID">
            <generator class="native"/>
        </id>

        <property name="name" />

    </class>


a child can be added to the parent and Hibernate will issue all the
necessary SQL requests. However, in order to remove a child, I have
to explicitly remove it from the parent first and then delete it.
This is what I was trying to avoid, since at the point of deleting the child,
I have no direct reference to the parent, and I cannot get Hibernate
to detect (using its model meta data) that the child is a member of some
parent children's collection and then remove the entry automatically.
Futhermore, if the inverse=true is set in the mapping of children, then
Hibernate assumes that the child manages the relationship, which it isn't,
in my case at least.

I think I have to conclude that what I'm trying to accomplish is not
possible and I have to do some of this work myself...

I'd appreciate this if you could confirm and I can vote this issue...

_________________
Cheers,

Bonny

please don't forget to rate :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 16, 2006 9:36 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
It's true that Hibernate can't remove the child from the parent's set, if there is an in-memory parent object. Much of the time (at least when working with webapps), hibernate won't even know about the parent object, since it will have been detached or even loaded in a different session. The most common way to delete an element in a set like this (one-to-many unidirectional association) is to have the set cascade all-delete-orphan, then remove the child from the parent's set and flush the parent. There wouldn't even be a deleteChild method. Obviously this doesn't help you, but you may find that conforming to that way of working will solve your problem.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 11, 2007 4:45 pm 
Newbie

Joined: Thu Jan 11, 2007 4:35 pm
Posts: 3
Location: Canada
Hello bonnyr,

At the end of this thread you walked without a real solution.

Did you find any convenient solution to this, or did you have to write yourself the code that would delete the child from all the parents (again speaking about the child(s) that do not know about their parents)

thanks for your answer


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 22, 2007 11:41 am 
Newbie

Joined: Mon Jun 26, 2006 4:52 am
Posts: 8
Hi,

Same problem for me. I have a unidirectional many-to-many relationship between objects. If I remove a child, I want to clean all remaining foreign keys from the association table ...

In SQL it would be simple and looks like that:
delete from PARENT_CHILD_TABLE where CHILD_ID=xxx ;

I don't see how I can obtain the same query with HQL??

regards
ju


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 22, 2007 4:21 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
You can either use the <sql-delete> element in the child's class, or make it a bidirectional relationship. You can hide the inverse relationship from the user API, and it will still delete the rows in the link table.

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


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 23, 2007 6:03 am 
Newbie

Joined: Mon Jun 26, 2006 4:52 am
Posts: 8
Thanks for your answer.

I guess using straight SQL won't work with the cache enabled on my collections, as it will go around the Hibernate objects.

Can you develop on the bidirectional relationship with an hidden part on one side ?

Many thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 25, 2007 4:22 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Develop the mapping and class as normal, with a bidirectional association. If you're using separate interfaces and classes, just don't put the getParents()/setParents() methods in the interface; if you're just using a class, then make those methods protected. Hibernate can still use the methods to maintain the relationship (and thus to do any cascading or link-table-deletions that you need), but they won't be in the public API, so as far as users are concerned, the relation is unidirectional.

_________________
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.  [ 13 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.