-->
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.  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Limiting the depth of a parent/child load request
PostPosted: Fri Mar 03, 2006 4:52 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 5:13 am
Posts: 22
Hello

I have a problem, which I would appriciate some help with if anyone has it.

I have a parent/child relationship. Since the depth can be up to 10 or even more sometimes I dont want to send all levels over to the client but instead use lazy loading when the user goes deeper in the tree. In the request from the client I receive a level indicator saying how many levels should be loaded.

The enteties are cached in the second level cache (EHCache) and in the request I get the root entity to load. I do a session.load(Object) on the root eneity. Since the entire structure is available in the cache I cant really detach any of the child enteties before sending them over to the client.

So how should I do this then?

I was thinking that in the writer- and reda external methods (I use RMI) i could just write to the specified depth but then the entity would have to know to which depth it should write itself to, which makes an ugly solution since I would need some global indicator for this.

Should I maybe do a clone on the root after loading it and just cloning to the specified depth?

Is there any direct Hibernate solution for this so I can do a load request and get only a specific depth. I guess not since it always load the entire level depth. Any way, any suggestions on this?

Regards
Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 5:14 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
so your question is how to serialize a java object only to a certain level? right? if you mark your attributes as "transient" they won't get serialized. Not sure how this would affect hibernate's non-lazy loading...

just a thought.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 5:54 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 5:13 am
Posts: 22
Hi

Well not really. first of all i dont use the Serializabel interface since it to slow I use Externalizable. The question is how can I limit the depth found from the database.

Since I have a parent/child relationship I woul either like to limit the depth I receive back directly from the database when doing load OR reading everything in to the second level cache on the first hit and when writing everything to the client only write the desired depth to the object stream.
One way of doing it would be to use lazy loading and the manually eager fetch only to the desired depth and then in the writeExternal method check if the child set is a proxy and in that case just skip writing it.

Any clearer?

Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 5:56 pm 
Beginner
Beginner

Joined: Thu Jul 08, 2004 2:21 pm
Posts: 20
Location: Toronto
As far I can see from your description, you want to limit the amount of data transferred to client side (you mentioned RMI).

You can not rely on hibernate cache, unless client have access to hibernate session. In your case you will transfer object via RMI to client side and close the session. So you need not just detached from session object, but you need a new object.

There is a good approach to this problem, you should use DTO (Data Transfer Objects). And don't try to transfer an object that you got from the session, since it is a complex object where some properties may be replaced by proxies.

The logic is simple:
you retrieve Hibernate object, copy properties into your DTO and transfer it to client side.

Also using this approach you can optimize amount of transferred data via RMI, for instance you can have a method that return only root instance, and another method that return root plus all children. It will speed up your application also.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 6:17 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
magpor wrote:
The question is how can I limit the depth found from the database.


wonder if the hibernate.property: hibernate.max_fetch_depth
would help? here is the description from reference.pdf
Quote:
Set a maximum "depth" for the outer join fetch tree
for single-ended associations (one-to-one, manyto-
one). A 0 disables default outer join fetching.
eg. recommended values between 0 and 3


Seems fairly static, however, and sounds like you want it configured per class (at runtime).

Not sure...sorry. If I think of something I'll let you know.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 6:45 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
magpor wrote:
Well not really. first of all i dont use the Serializabel interface since it to slow I use Externalizable.


Serializable is the Superinterface of Externalizable - and as such transient should work fine... at least something to expirment with... right?

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 6:52 pm 
Beginner
Beginner

Joined: Sun Feb 19, 2006 5:13 am
Posts: 22
hibernate.max_fetch_depth only says how deep the join should be when fetching a parent /child replationship. It will spped up the access to the database by generating fewer sql statements.

No, I think this has to be solved in the writeExternal method but then I will get a dependency to Hibernate libraries in my DTO objects, wihch I dont like t all. hmmmm...will have to sleep on it :-)

Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 7:02 pm 
Beginner
Beginner

Joined: Thu Jul 08, 2004 2:21 pm
Posts: 20
Location: Toronto
magpor wrote:
hibernate.max_fetch_depth only says how deep the join ...

Won't help you at all.
magpor wrote:
No, I think this has to be solved in the writeExternal method but then I will get a dependency to Hibernate libraries in my DTO objects, wihch I dont like t all. hmmmm...will have to sleep on it :-)
Magnus


It is the best approach to implement your DTO in a way that you can pass Hibernate Object as constructor parameter and DTO will copy required values.
I used this approach in numerous projects, it sounds a lot of work, but when you done it, make a lot of sense.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 7:27 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
So, perhaps in conjunction with creating the DTO you use reflection to search for "collections" in the object (1st level), then recurse to the desired level - writing into the DTO... Also, I'd make sure to catch the LazyInitialization exception, upon hitting uninitialized objects.

This way there is no hibernate dependencies, except the catch for lazy...

by the way, Ivan, sounds like you know about the "max_fetch_depth" parameter - can you explain why it won't work? Just curious - I've never tried it, but seems like it might suite the need to stop the levels inits. Guess I am mis-reading the manual, yet if it doesn't fetch at the level, it won't initialize...

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 7:54 pm 
Beginner
Beginner

Joined: Thu Jul 08, 2004 2:21 pm
Posts: 20
Location: Toronto
max_fetch_depth only affect how and when proxy will be initialized, but it won't stop it from initializing.

The object that hibernate return on your query is a complex object when almost always you will see a proxy instead of an association.

This parameter will detemine how many proxies will be initialized right away. But if you call not-initialized proxy it will fetch the data for you.

When magpor is needed a DTO.

b.t.w. no need to use reflection when building DTO and no need to catch lazy exceptions because DTO must be build with open session.
It will look something like this:

Code:
Session session = hibernateService.openSession(); // get the session
MyOject object = session.get(MyOject.class, ID); // load Hibernate Object
MyDTO dto = new MyDTO(object); // create DTO from loaded object
session.close(); // close session

return dto; // return DTO, that has no relation with session at all


and DTO could look like
Code:
public class MyDTO {
  protected String name;
  protected Set children;
  public MyDTO(MyObject object) {
    this.name = object.getName();
    ....
    this.children = new HashSet(object.getChildren().size());
    for (Object child : object.getChildren()) {
      ChildDTO _child = new ChieldDTO(child);
      this.children.add(_child);
    }
    // or if children are simple type
    this.children = new HashSet(object.getChildren().size());
    this.children.addAll(object.getChildren());
  }
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 9:03 pm 
Regular
Regular

Joined: Wed Feb 08, 2006 3:59 pm
Posts: 75
I had a similar issue and this is the approach I used :

- All classes implement Externalizable (you already do that)
- In writeExternal(), if an association is initialized, write it, else write null (check with Hibernate.isInitialized(object)).
- Fetch associations you want to initialize (using HQL fetch construct, or by accessing fields in POJOs), as deep as you want.

The major issue with this solution is that one client side, you get null references in associations that may actually not be null, but if you want to fetch relations at XX levels, I think you expect it anyway.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 9:05 pm 
Expert
Expert

Joined: Mon Jan 09, 2006 5:01 pm
Posts: 311
Location: Sacramento, CA
IvanLatysh wrote:
max_fetch_depth only affect how and when proxy will be initialized, but it won't stop it from initializing.


Thanks for the explanation - I was thinking that once you loaded the object and closed the session (thus now detached object), then the items that aren't initialized would throw the lazy exception & he could deal with them that way.

Are you saying that if I load an object and I have this level set to 1, for instance, that the child objects, say 2 or three levels deep will still be initialized regardless of this setting? (I would have thought that this flag would overide lazy="false" on the collections, which makes perfect sense in my mind).

I am curious about this because the docs don't say that it would or wouldn't be initialized, and I was assuming that it wouldn't.

_________________
-JT

If you find my replies helpful, please rate by clicking 'Y' on them. I appreciate it.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 04, 2006 4:33 am 
Beginner
Beginner

Joined: Sun Feb 19, 2006 5:13 am
Posts: 22
Hi

According to documentation:

Quote:
maximum_fetch_depth

Set a maximum "depth" for the outer join fetch tree for single-ended associations (one-to-one, many-to-one). A 0 disables default outer join fetching.eg. recommended values between 0 and 3


This means that Hibernate will use out-joins to fetch the tree. That is when fetchin for examp,e 2 leveles and having maximu_fetch_depth 2 or 3 HIbernate will fetch the entire tree using one sql request. This is my interpretation of maximum_fetch_depth.

Yes I could use writeExternal like this but then I need to export all Hibernate libraries to my Swing client since I dont use DTO objects the way you are doing. I want to use the same object that is persistet on the client also.
Im thinking that I should some how use a external entity for writing to the stream, and on the server I can use it the wayyou just describe but on the client I just write everything to the stream.

Magnus


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 04, 2006 5:18 am 
Regular
Regular

Joined: Wed Feb 08, 2006 3:59 pm
Posts: 75
I use the writeExternal solution and have 0 dependices to Hibernate on client side. The client gets POJOs and has no knowledge of proxy classes.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 04, 2006 5:39 am 
Beginner
Beginner

Joined: Sun Feb 19, 2006 5:13 am
Posts: 22
But then you are using DTO objects, which you get from the server or?

Hmm what I mean is that thw writeExternal method needs to use hibernate.initialize, right? And if Im using the same class on both client and server I will have a dependency to Hibernate, or what do you think?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 23 posts ]  Go to page 1, 2  Next

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.