-->
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: How add child using cascades when 100s of children
PostPosted: Wed Jul 28, 2004 12:13 am 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
Hi, question about using cascades and performance, situation:

Parent has a one to many relationship to children, it is not bidirectional, so children do not have a reference back to the parent.

The cascade is set to all-delete-orphan.

There is potential to have 100's or even thousands of children associated with the parent, the children don't hold much data but Id rather not clog stuff up unless I have to. Is it possible to add a child to the parent by adding it to the parents list then saving it without loading the whole list of children? Or can anyone think of a better way to do this?

Thanks,
David


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 4:09 am 
Expert
Expert

Joined: Fri Feb 06, 2004 7:49 am
Posts: 255
Location: Moscow, Russia
Have you read this 14.1. Understanding Collection performance?
http://www.hibernate.org/hib_docs/reference/en/html/performance.html#performance-collections


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 12:06 pm 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
Yes I've read that, the problem I'm running into though is that Hibernate wants to load the collection of potentially 1000's of children before i can do a .add(child) to it, which is not performant at all. I'm thinking maybe I'm going to have to make the collection bidirectional and mark the child end as inverse=true so i can just update it from there without needing to load the full list on the parent side.

any ideas?
-David


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 1:26 pm 
Regular
Regular

Joined: Tue Oct 28, 2003 8:25 am
Posts: 72
Location: Belgium
Making the collection bidirectional won't avoid having to load the collection.

Doc chapter 16.2 explains you the idea behind the bidirectionality/inverse=true idea.

It is possible to avoid having to load the collection when adding a new object in it by mapping it as a bag, see chapter 14.1.3. But bags come with other annoying performances problems described in 14.1.1.

This is a problem that I generally workaround by only mapping the many-to-one relation and using only HQL for fetching the objects I need.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 1:32 pm 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
In my situation I won't ever need to retrieve all of them, at MOST maybe 1 at a time.. however if I have to retrieve all of them to add another that could be very non performant.. what did you do about adding?

and when you say you only mapped the many to one, do you mean you only have a link from child->parent and parent doesnt' necesarily know about the children?

Thanks,
David


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 1:37 pm 
Regular
Regular

Joined: Tue Oct 28, 2003 8:25 am
Posts: 72
Location: Belgium
Quote:
and when you say you only mapped the many to one, do you mean you only have a link from child->parent and parent doesnt' necesarily know about the children?

Correct.


Quote:
what did you do about adding?

Simply set the parent in the child when creating a new one.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 1:55 pm 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
And then I'm assuming to grab children based on their parents you did something like

select c from Child c where c.parent=:parent
?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 2:12 pm 
Regular
Regular

Joined: Tue Oct 28, 2003 8:25 am
Posts: 72
Location: Belgium
Exactly.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 28, 2004 2:47 pm 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
Thanks =)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 29, 2004 9:45 pm 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
To continue this thread I thought I would present my exact problem since I'm not sure I can do it with the above solution.

Here's the situation, I need to store 'Vote' objects that contain a few small strings. These vote objects MUST be tied somehow to a parent object, and that parent object is one-to-one'd with a user object.

1) If I have a vote.parent property and a many-to-one mapping in the vote mapping file I can add the vote easily by setting the parent. However the problem comes when I need to delete, since there is no top down connection if I delete the user object it will cascade and delete the parent object however that cascade will not continue to the vote object. So I'm stuck loading all the votes (could be 1000's or even 100's of thousands), and then sending them to session.delete 1 by 1, VERY not performant.

2) If I chose to map parent.votes as a bag, the cascaded deletes would work, however I Just noticed this in the docs section 14.1.1:

Quote:
Bags are the worst case. Since a bag permits duplicate element values and has no index column, no primary key may be defined. Hibernate has no way of distinguishing between duplicate rows. Hibernate resolves this problem by completely removing (in a single DELETE) and recreating the collection whenever it changes. This might be very inefficient.


I can't imagine re-inserting 1000's+ of records everytime I add to the bag to be performant.

3) I thought about using a many-to-many relationship and setting the vote end as inverse, since it would only ever be setting one parent thats not a big deal (weird model but it might work). However querying with that situation seemed very difficult, ie would this even work??):

Code:
selct user.id from Vote vote left join fetch vote.parents p left join fetch p.user where vote.property <> :value and p.property='1'


Any help greatly appreciated,
David


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 30, 2004 12:10 am 
Regular
Regular

Joined: Wed Dec 17, 2003 1:58 pm
Posts: 102
Ok solved.. I decided to go with the many-to-many mapping feature, because

a) I'll NEVER load the list of votes from the parent object side.. and I can just leave it as lazily instantiated and not worry about it.

b) If the parent gets deleted I have the cascade set to all-delete-orphan so hibernate will mass delete the votes without having to load them

c) I set the vote side to inverse="true" so to add a vote all i need to do is create a vote and then add the parent object to its list and wallah its saved without having to load anything. Because I only ever want the vote to belong to one parent, I have no getters/setters for the set, and its marked private. I have methods like this:

Code:
  public Parent getParent() {
    if ((parents != null) && (parents.size() > 0)) {
      for (Iterator it = parents.iterator(); it.hasNext();) {
        return (Parent)it.next();
      }     
    } else {
      return null;
    }
    return null;
  }

  private void setParent(Parent p) {
    Set set = new HashSet();
    set.add(p);
    profiles = set;
  }


In this example my Vote object is immutable so the setParent is only ever called from my constructor.

Hope this helps someone down the road that ever has problems!
-David


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.