-->
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.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Graph subset fetching
PostPosted: Sat Jul 09, 2005 1:31 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
Here is something that NHibernate probably supports (I can't imagine it wouldn't) but I can't figure out how to do it.

Suppose I have an NHibernate class and it has several many to one properties. Each of these properties has several many to one properties and so on and so on. You can imagine that this object graph can get very extensive.

I want to be able to fetch this class and specify which of these many to one properties to load and which not to load. When I get this class instance the many to one properties that I haven't fetched will be marked as unavailable.

I would also like to selectively load regular properties (not one to one, not many to one and not one to many) in both the top level class instance and any other class instances in the object graph.

Please don't tell me that HQL can do this becau it can't. If you select specific fields from an object in HQL then the result is not the class instance but rather a flat object array representation.

There must be a way to do this. If NHibernate cannot do this then it is a por exceuse for an ORM. There is no reason I should have to fetch reams and reams of data if I only need a small subset of it. There is also no reason I should have to put up with a flat representation of data if I need a subset of the graph.

At my previous employer we had an in-house developed ORM and it could do everything I just described.

Thanks in advance for any help you can offer.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 09, 2005 1:43 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Of course it can do what you want, but not the way you did it. Read the documentation on proxies.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 09, 2005 4:59 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
Thanks for your reply. I am now scouring the internet looking for examples of how to use proxies in order to achieve my objectives. I haven't been able o find anything yet.

I wish there was a comprehensive NHibernate book. That would make my life easier.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 09, 2005 5:24 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
I just looked thru the online documentation and there isn't even a shred of an example on how to use proxies to achieve what I want. I also looked for the last couple of hours on the internet and haven't found even a whiff of an example on how to achieve this.

I am very disillusioned with NHibernate. Selective loading of properties is something very basic and should not be so elusive. By what I've read in the documentation, proxies will not give me what I want. I want to pre-load selected properties (in the object graph at any level). I don't want these properties to be fetched one at a time as I use them, this will create too many database hits.

Sorry for my sour tone but I'm truly dumbfounded at how a supposedly mature ORM like (N)Hibernate does such a poor job of this. The in-house ORM I used at my last employer made selective property fetching very easy. All you had to do was use the supplied API to specify which properties you wanted (using the dot notation to specify properties in deeper levels of the object graph)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 11:44 am 
Contributor
Contributor

Joined: Thu May 12, 2005 9:45 am
Posts: 593
Location: nhibernate.org
Are you talking about this:

http://www.hibernate.org/hib_docs/v3/reference/en/html/performance.html wrote:
20.1.7. Using lazy property fetching
Hibernate3 supports the lazy fetching of individual properties. This optimization technique is also known as fetch groups. Please note that this is mostly a marketing feature, as in practice, optimizing row reads is much more important than optimization of column reads. However, only loading some properties of a class might be useful in extreme cases, when legacy tables have hundreds of columns and the data model can not be improved.


This is a new feature of Hibernate 3.0 and as NHibernate is a port of Hibernate 2.1 it doesn't have it.

And note that it is possible to force the initialization of proxies with eager fetching...

_________________
Pierre Henri Kuaté.
Get NHibernate in Action Now!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 1:05 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Well, NHibernate doesn't do selective loading of properties. It loads the whole object, but uses proxies for the objects and collections that are referenced by the loaded object. Proxies are created without touching the database, and later when they are accessed the whole object is loaded from the database (using a single SELECT).

This is similar to selective property loading and is easier to understand, use and implement. You really shouldn't become disillusioned with the whole technology just because it doesn't work exactly the way you want, try to understand it first. When you start using phrases like "a poor excuse for an ORM", you are only going to offend the developers for no good reason.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 1:42 pm 
Like I said, I already have extensive experience with ORM, I used an in-house built ORM that could easily do selective loading of properties. Actually, at first our ORM did not have this feature and all the developers complained about it, so the in-house developer that developed our ORM quickly added that ability.

Actually, my main concern is not with selective loading of regular properties, it is with selective loading of many-to-one relationships. If I'm forced to load all of these then I will be in a situation where all the object graph gets loaded where in fact I just need a small subset of it. Lazy loading is not the answer for me becuase I need the ability to pre-load the graph subset so that only one database fetch is done.

Well thanks for your input, it looks like NHibernate is not the right tool for enterprise applications that require efficient database fetching.


Top
  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 1:55 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
By the way, selective pre-loading of many to one properties is not just a marketing feature it is essential for creating fast and scalable systems. If I have an objecty graph with 100 many-to-one nodes (very realistic if you go 4 or 5 levels deep) then why would I want to generate joins for all these nodes if I just need 3 or 4 of these nodes?


Lazy loading is not the answer becuase I want to pre-load all of my nodes with one SQL statement. I don't want to hit the database each time I use nodes in my class instance

Just out of curiosity, are there any large enterprise systems out there that have been written exclusively with (N)Hibernate? Do any of these systems need to operate in an environment where scalability is a very important requirement? For example, do any of these systems need to accomodate 1000 users hitting the same functionality all within the space of one minute?

I guarantee you (from personal experiece on the job) that any ORM that does not allow subset PRE-LOADING (not lazy) of an object graph will not be usable in such an environment. This is the real world. This is what an ORM needs to do in order to be usable in highly demanding environments.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 4:53 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
Quote:
Lazy loading is not the answer becuase I want to pre-load all of my nodes with one SQL statement. I don't want to hit the database each time I use nodes in my class instance


One school of thought in mapping the object graph is that all collections are lazily loaded. Then using HQL within a DAO pattern, you can create methods that instantiate the object and its "customized" graph using eager fetching and the various params that you can associate with the HQL (batch size, etc). So, in essence, I politely disagree with your statement and posit that highly customized HQL wrapped in a DAO might be the answer to your need.

Using this strategy, you never really end up paying the penalty of lazily loading an entire collection if your HQL is correct. The only penalty you pay is the need to write customized HQL methods for each "instantiation" based on whatever customized obect graph you might need in the particular instance.

Also, I would try and stay away from using the terminology of "Property" for a m-1/m-m/1-m collection association. I think, in this instance, it has added a bit of confusion. the H3 feature is specifically addressing a Property like "string Name", or "int ID" and not "IList children."

Selective pre-loading of many-to-one properties already exists in my opinion.

Quote:
Just out of curiosity, are there any large enterprise systems out there that have been written exclusively with (N)Hibernate? Do any of these systems need to operate in an environment where scalability is a very important requirement? For example, do any of these systems need to accomodate 1000 users hitting the same functionality all within the space of one minute?


I currently have a system, written entirely on NH that operates in an environment where scalability is important. On a single server, dual p4 running Win2003/IIS/SQL2000 _on the same box_ can handle over 1000 requests per second to the same "feature" -- our most complex feature-- without really breaking a sweat. In fact, we've maxed out the gigE card before maxing out the processor or internal raid. This is on a development machine and we don't even have the second-level cache enabled on that box. In our production envirnoment we can handle much more since the IIS functions are separated from the application functions separated from the db functions and the jcs cache is in use.

Quote:
This is the real world. This is what an ORM needs to do in order to be usable in highly demanding environments.


I can understand your frustration but seriously, Hibernate is the de facto standard for ORM in the Java space. Mike, Sergey, et al are doing their best to port that code base over to .NET. What this system really needs are more developers. I personally am hoping to devote some of our team development cycles once our app is finished. More developers would be a tremendous help to this platform. NHibernate will be solid, it is in beta form at the moment so perhaps it just isn't ready for your envirnoment.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 5:34 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
I truly feel like I'm in the twilight zone. All of you on this board are expressing the sentiment that what I'm asking for is not that crucial but in my mind it isn't just a nice to have it is an absolute must.

Imagine writing an SQL statement that uses many levels of joins to retrieve a table graph to a very deep level but all that is needed is just one field from the top level table. You wouldn't dream in a million years to be writing such a wasteful SQL statement. Why then is that the defacto standard for the ORM world?

I'm sorry but I'm left just shaking my head in bewilderment.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 8:42 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
Nissim, I am genuinely trying to help you here. I don't think I ever expressed the sentiment that what you are asking for is not an absolute must. I am actually trying to help you find the solution.

Quote:
Imagine writing an SQL statement that uses many levels of joins to retrieve a table graph to a very deep level but all that is needed is just one field from the top level table. You wouldn't dream in a million years to be writing such a wasteful SQL statement. Why then is that the defacto standard for the ORM world?


I don't think I'm following you. If I understand your question, you are asking about selectively fetching a property that is actually an object. Eg
Code:
public class Foo {
  private Object bar;

  public Foo() {};

  public virtual Object Bar {
    get { return this.bar; }
    set { this.bar = value; }
  }
}

<class name="Foo">
  <id ...>
    <generator ... />
  </id>

  <many-to-one name="Bar" class="Bar" />

</class>


There is no way that I know of to hydrate the object Bar without a join. The table definition for Bar most likely has a PK->FK to the table for Foo. Hence when instantiating Foo you have to JOIN to Bar to instantiate Bar. I guess I'm not really understanding how you are proposing to instantiate Bar without a join.

The only way I can think of to prevent the join from happening automaticlly would be to change the mapping of Bar to:

<many-to-one name="Bar" class="Bar" outer-join="false" />

This will prevent the join if and only if the object already exists in the second-level cache. Once you reference the Foo.Bar property however, and Bar isn't in the second-level cache, blammo you've been JOINed.

But, sticking with my original comment, trying to specify the fetching strategy in the mapping file is not always the best strategy. Using HQL and applying fetching stratagies for the particular HQL or ICriteria.Criteria is a better way to go. Eg:

using HQL, I would set proxying/lazy-fetching on all relationships. Then write something like:

from Foo foo
left join fetch foo.bar
left join fetch foo.otherBar

This is the only way I know of in NH 2 to selectively load many-to-one relationships. Going deeper that the first level is up to you to work on.

Again, I'm rying to help you get what you want. I'm not making any kind of judgement about whether or not your request is valid.

-devon


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 9:06 pm 
I'm sorry if I seem like a grouch. It's just that I'm very frustrated because I've already committed the project to NHibernate and now I'm having all these performance issues. I appreciate your help.


Your example below is intriguing me:

using HQL, I would set proxying/lazy-fetching on all relationships.
Then write something like:

from Foo foo
left join fetch foo.bar
left join fetch foo.otherBar

Are you saying that if I use HQL like this then it will force NHibernate to join only to the classes that I explicitly mention. If this is true then my problem with the many-to-one issue is solved.

If I were to rewrite the statement you gave as follows:

from Foo foo
left join fetch foo.bar

will the join to foo.otherBar be prevented. Secondly, will the result of the HQL you wrote return a Foo instance and not a flat object array?


Thanks for your help


Top
  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 9:07 pm 
Newbie

Joined: Sat Jul 09, 2005 1:17 pm
Posts: 17
That's me above. I forgot to log in.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 10, 2005 10:25 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
Quote:
If I were to rewrite the statement you gave as follows:

from Foo foo
left join fetch foo.bar

will the join to foo.otherBar be prevented.


Yes, assuming, as you said, that you map all relationships as lazy and turn proxying on for every object. (Don't forget to make all of your Properties virtual...)
Quote:
Secondly, will the result of the HQL you wrote return a Foo instance and not a flat object array?


Yes. And you can even limit it to a single instance of Foo (instead of a collection of Foos) if you want by adding a where clause specifying a property of Foo:

Code:
from Foo foo
left join fetch foo.bar
  where foo.id = 1


you can return an IList of Foos by specifying a where clause that matches several Foos:

Code:
from Foo foo
left join fetch foo.bar
  where foo.id > 1


There are some distinct quirks in Hibenate, and there are some specific quirks to NHibernate since we are still in beta, but I still think NH is one of the bext ORM tools out there.

Since you are having performance issues, I would also encourage you to also look into enabling the JCS cache. Martijn Boland (I may have mispelled his name) has an application Cuyahoga that actually stores hydrated objects in the ASP cache and reattaches them to ASP context sessions. That would work for you as well. (Assuming you are using ASP.NET...)

Also, if you have the time, buy Hibernate in Action. It is Java-specific but much of the information maps over to .NET. There are specific chapters on optimizing queries, fetching objects, and working with performance issues. Since you've been with an ORM tool before, you can probably skip much of the basic mapping stuff.

Cheers,

-devon


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 11, 2005 12:23 am 
Thanks Devon, that's great. You've been a great help. Just one last question.

Suppose I don't want to join to any of the many-to-one properties. I just want to fetch the regular properties of FOO. How can I do that? If I just write

from Foo foo

without any join statement, will I just get Foo's regular properties without any join baggage?

Thanks again for helping me out.


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