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.  [ 20 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Does Hibernate support a deep initialize of an object?
PostPosted: Mon Jul 25, 2005 4:27 pm 
Beginner
Beginner

Joined: Fri Feb 20, 2004 6:15 pm
Posts: 38
It's a very common question of how to completely detach an object for display to the view (or detach for some other reason).

The suggestions by Hibernate have been:
1. put lazy="false" in your mappings
2. explicitly access the properties and iterate the collections of the object you want to detach (which requires possibly many levels to completely access the object graph)
3. use #2 with some combination of Hibernate.initialize

I don't think any of these options (or any of the others present) are really sufficient for providing the ability to completely initialize an object graph starting at some node.

Is there anything that is similar to a deep-initialization of an object graph on demand? I've tried everything I've been able to find, but this just doesn't seem possible in Hibernate.

I'd like to see something like Hibernate.initializeAll(object) or Hibernate.deepInitialize(object) to make this easier on developers. It's messy code to do #2/#3 above, and it affects the rest of the application if you use #1 so it's not a good choice.

Again, this question has been asked several times, but I'm hoping to hear a good answer here as to whether Hibernate currently supports a deep initialize, and if not, whether there are any plans to do so.

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 4:42 pm 
Regular
Regular

Joined: Mon Apr 25, 2005 9:22 am
Posts: 62
Location: Bucharest/Romania
I would probably try to agree with you if it would be a way to avoid fetching the whole db :-).

I am inclined to agree with you that lazy=false is not solving this kind of problems. However using Hibernate.initialize is the most "customizable" way you can achive that. You cannot require a framework to decide for you the depth to which the graph should be traversed, so I guessed this decission was pretty smart to move the responsibility to the developer - the only one who knows where should start and where to stop.


just my 0.02 euroc

:alex |.::the_mindstorm::.|


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 5:00 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
HQL and Criteria are Hibernates "fetch plan" mechanisms. Very flexible, but both of you seem to have missed it completely.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 5:20 pm 
Regular
Regular

Joined: Mon Apr 25, 2005 9:22 am
Posts: 62
Location: Bucharest/Romania
Please correct my if completely wrong: the LazyInitialization exception will not be disappear for a collection scenario with lazy=true and FETCH ALL.

:alex |.::the_mindstorm::.|


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 5:28 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
FETCH ALL has nothing to do with collections.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 5:34 pm 
Regular
Regular

Joined: Mon Apr 25, 2005 9:22 am
Posts: 62
Location: Bucharest/Romania
So what should I understand from your above post?

As far as i understood fetch is the number of instances to be created/returned upon a query. In case of a real object this is clear, with collections these are in fact proxies. Am I wrong? (i can definitely at least agree on this :-)).

Or should I read/understand something else from 'fetch plan'?

thanks,
:alex |.::the_mindstorm::.|


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 5:54 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Hibernate3 loads a single entity instance if you retrieve it by identifier through get() or load(). All collections mapped for this entity, and all associated entities, be it through -to-many or -to-one associations, are not loaded. For collections there are "wrappers" in place, for single-ended associations, "proxies" are used by default.

If you then navigate from the loaded entity instances to a collection (and iterate through it), or to a single associated second entity, an additional SELECT will be executed to fetch exactly what you just hit in your code. This effectively produces n+1 selects.

Two different and complementary ways to change this behavior:

1. Go into your mapping and change the _global_ behavior of a particular collection or association. We have two notions: What should be fetched and how should it be fetched:

- You can switch to an _immediate_ non-lazy second SELECT by setting lazy="false" on a collection. You can switch to an _immediate_ non-lazy second SELECT for single-ended associations by disabling proxies on the target entity (<class name=B lazy=false>).

- With a batch-size on a collection or on a class mapping you tell Hibernate to optimize the second SELECT by fetching up to n other collections (or entity instances) when you hit one in Java, depending on how many you expect to be in the Session already. This is a blind-guess optimization technique, but very nice for nested tree node loading.

- With fetch="subselect" on a collection you can tell Hibernate to not only load this collection in the second SELECT (lazy or non-lazy), but also all other collections for all other entities of the same type you loaded in the first SELECT. This is especially useful for "serial" collection fetching.

- Setting a collection or -to-one association to fetch="join" will actually avoid the second SELECT, but use just one "bigger" outer-join SELECT to get both the owning and the referenced entity instance (or collection). If you fetch="join" more than one collection for a particular entity instance (both in "parallel"), you create a Cartesian product and two SELECTs would probably be faster.

2. You can override or completely redefine the "what is loaded" and "how is it loaded" using APIs programmatically, at runtime:

- Criteria respects the laziness settings in your mappings and guarantees that what you want loaded, is loaded. This means one Criteria query might result in several SQL immediate SELECTs to fetch the subgraph with all non-lazy mapped associations and collections. If you want to change the "how", use setFetchMode() for a particular property.

- HQL respects the laziness settings in your mappings and guarantees that what you want loaded, is loaded. This means one HQL query might result in several SQL immediate SELECTs to fetch the subgraph with all non-lazy mapped associations and collections. If you want to change the "how", use "left join fetch" for outer-join fetching of particular collections or -to-one associated entities.

Finally, there are more advanced settings:

- lazy="true" on -to-one associations and <property> mappings, used with bytecode instrumentation as an alternative to proxies and for lazy loading of individual scalar properties (both somewhat exotic)

- lazy="extra" on collections for "smart" collection behavior, i.e. some collection operations such as size(), contains(), etc. do not trigger an initialization of the collection, but execute additional SQL

- some more exotic optimizations you will find out when you know more about Hibernate, but the above is 95%

Now, if you want to do something good, put this on the Wiki as "A short primer on fetch strategies". Thanks


Last edited by christian on Mon Jul 25, 2005 6:03 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 6:01 pm 
Senior
Senior

Joined: Thu May 12, 2005 11:40 pm
Posts: 125
Location: Canada
It is possible to fully define exactly what you want returned in your object graph using HQL 'join fetch' or criteria FetchMode.JOIN.

select foo
from Foo foo
left join fetch foo.bar bar
left join fetch foo.baz baz
left join fetch bar.qux qux
left join fetch qux.fred fred
where ...

The only exception is where you need to eagerly fetch more than one collection rooted in the same node. You can only do one, because with two Hibernate has to do an uncorrelated join which results in a cartesian product.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 6:02 pm 
Regular
Regular

Joined: Mon Apr 25, 2005 9:22 am
Posts: 62
Location: Bucharest/Romania
Yep i will do that, but firstly i need to understand it :).

thanks for your time,
:alex |.::the_mindstorm::.|


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 6:45 pm 
Senior
Senior

Joined: Tue Jun 21, 2005 10:18 am
Posts: 135
Location: South Carolina, USA
christian wrote:
HQL and Criteria are Hibernates "fetch plan" mechanisms. Very flexible, but both of you seem to have missed it completely.

When I was first starting out with Hibernate, I missed this completely as well. Not through any fault of the documentation, I don't think. It just took me a while to catch on. *shrugs*


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 25, 2005 6:48 pm 
Regular
Regular

Joined: Mon Apr 25, 2005 9:22 am
Posts: 62
Location: Bucharest/Romania
Done: http://www.hibernate.org/315.html. Many thanks. (however I may say that I was not wrong but incomplete :-) ).


:alex |.::the_mindstorm::.|


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 26, 2005 6:00 am 
Beginner
Beginner

Joined: Fri Feb 20, 2004 6:15 pm
Posts: 38
christian wrote:
HQL and Criteria are Hibernates "fetch plan" mechanisms. Very flexible, but both of you seem to have missed it completely.


I'm not saying that what is there is not flexible.

I'm saying that there is still a lack of an initializeAll or deepInitialize method. There is not a convenient way to just say give me the complete object graph initialized. Although that could be a very expensive method, it would still be nice to have for when a developer understands the potential cost and wants to do this.

I think this would be very useful and also answer a lot of questions / solve problems that users have.

This way you'd have
1. a simple way to lazy load everything (or whatever configuration you have in your mapping files)
2. a simple way to load everything initialized (via this new deepInitialize method)
3. a very flexible way to specify what you want loaded through HQL / Criteria for those cases where you have more complex needs


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 26, 2005 6:18 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
You seem to think that this is something that can be done automatically. I guess you are not aware that an object network is a _graph_, with circular references etc. What you think is "deep initialization" is in almost all cases "load the whole database into memory". Just declare what you want in HQL or Criteria, there is no other sensible way.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 26, 2005 6:34 am 
Beginner
Beginner

Joined: Fri Feb 20, 2004 6:15 pm
Posts: 38
christian wrote:
You seem to think that this is something that can be done automatically. I guess you are not aware that an object network is a _graph_, with circular references etc. What you think is "deep initialization" is in almost all cases "load the whole database into memory". Just declare what you want in HQL or Criteria, there is no other sensible way.


There are algorithms to detect circular references in a graph, so you can work around the problem. I understand that in many cases it would be "load the whole database into memory", but in some cases it would not.

You can automatically detect which fields through the Hibernate mapping files, so that is possible.

I think this is definitely possible. I agree it's probably not a good idea in most cases. It would be nice for some other cases though.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 26, 2005 7:21 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
In any nontrivial app this would be *incredibly* undesirable and would result in atrocious performance.

We certainly do not provide functionality like Session.shootMyselfInTheFoot().


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 20 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.