-->
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.  [ 10 posts ] 
Author Message
 Post subject: Many-to-One lazy loading
PostPosted: Fri May 12, 2006 11:13 am 
Beginner
Beginner

Joined: Fri May 12, 2006 10:48 am
Posts: 33
Hello, I’m working with NHibernate and VB.Net. I need to load a many-to-one property in a “lazy” way and I don’t know how I can develop it.
I was looking for a code example using a proxy class but I couldn’t find it.
Could anybody share an example?


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 12, 2006 3:56 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
as far as I know, you can't really define a m-1 relationship as lasy, however you can prevent it from being loaded by using "outer-join=false" setting.

One thing you could try would be to declare the lazy attribute in the class of the m-1:

Code:
<class name="childClass" lazy="true">
    <bag name="parents" lazy="true" inverse="true">
        <one-to-many class="parentClass" />
    </bag>
</class>

<class name="parentClass">
    <many-to-one name="child" class="childClass" />
</class>


if that doesn't work, i know

Code:
<many-to-one name="child" class="childClass" outer-join="false" />


will prevent the class from being loaded. However, you sort of rely on that class being in the second-level cache if you need to reference it...

-devon


Last edited by devonl on Tue May 16, 2006 2:42 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat May 13, 2006 12:10 pm 
Beginner
Beginner

Joined: Wed Oct 05, 2005 5:35 am
Posts: 47
Location: France
Hmmm... Shouldn't many-to-one be lazy if the class is defined as lazy? Let's say you have Person and Title:

Code:
<class name="Person" table="Person" lazy="true">
     <id name="Id" column="Id">
         <generator class="identity" />
     </id>
     <property name="Name" column= "Name" />
     <many-to-one name="Title" class="Title" column="TitleId">
     </many-to-one>
</class>
<class name="Title" table="Title"  lazy="true">
     <id name="Id" column="Id">
         <generator class="identity" />
     </id>
     <property name="Name" column= "Name" />
</class>


Title is defined as lazy="true" in class element, so a <many-to-one> from Person will be lazy... No? That's how it works in my code anyway...


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 15, 2006 11:53 am 
Beginner
Beginner

Joined: Fri May 12, 2006 10:48 am
Posts: 33
Hi, thanks for your reply.
I’ve tried to do it but I have some trouble.
I defined my classes as follow

<class name="Provincia" table="Provincias">
<id name="Id" type="Int32" unsaved-value="0">
<column name="idProvincia" sql-type="int" not-null="true" unique="true" />
<generator class="native" />
</id>
<property name="Descripcion" type="String">
<column name="Descripcion" length="60" sql-type="varchar" not-null="true"/>
</property>
<many-to-one name="Pais" class="Pais">
<column name="IdPais" sql-type="int" not-null="true"/>
</many-to-one>
</class>


<class name="Pais" table="Paises" lazy="true" >
<id name="Id" type="Int32" unsaved-value="0">
<column name="IdPais" sql-type="int" not-null="true" unique="true" />
<generator class="native" />
</id>
<property name="Descripcion" type="String">
<column name="Descripcion" length="60" sql-type="varchar" not-null="true"/>
</property>
<bag name="Provincias" inverse="true" lazy="true" cascade="none">
<key column="idProvincia"/>
<one-to-many class="Provincia"/>
</bag>
</class>

When I execute the following instruction
mySession.Find("from IAMCReportes.Common.Provincia as Provincia")
Only a select on Provincias table is done, that's correct. But when I try to access property Pais it is never loaded.
How can I load the Pais when it is required?


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 15, 2006 5:58 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
Quote:
How can I load the Pais when it is required?

That really depends on how you are building your application. Basically, you have to understand what is going on in the background with regard to lazy initialization. Lazy collections can be instantiated on the fly if you still have the original session open, but that isn't always the best method. In most instances, the preferred method is to build the entire object graph necessary before it is forwarded to the View ( as in the MVC pattern).

If you follow the recommendations of the Hibernate team, all associations should be mapped lazy and you should build specific HQL queries to return specific instances of object graphs necessary for a particular purpose. In your case, you might write an HQL like so:

Code:
mySession.Find("from IAMCReportes.Common.Provincia Provincia join Provincia.Pais Pais");


An alternative would be to use the session.Lock() method and then initialze the lazily loaded attribute (property).

In my opinion, you shouldn't be lazily loading the Pais. Paises don't change much (even with world politics being what they are). I'd feel pretty safe allowing Pais to be eagerly fetched on the m-1 association and instead enable a "read-only" cache on the Pais object. It isn't going to change much and if it does, it will almost certinaly require a restart of the app. This way, NH will load the Pais from the cache and not the database. You could do this with a simple change to the mapping file:

Code:
<many-to-one name="Pais" class="Pais" outer-join="true">
    <column name="IdPais" sql-type="int" not-null="true"/>
</many-to-one>


and the addition of the cache notation to the Pais mapping:

Code:
<class name="Pais" table="Paises" lazy="true" >
    <cache usage="read-only" />
    <id name="Id" type="Int32" unsaved-value="0">
        <column name="IdPais" sql-type="int" not-null="true" unique="true" />
        <generator class="native" />
    </id>
    ...


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 11:17 am 
Beginner
Beginner

Joined: Fri May 12, 2006 10:48 am
Posts: 33
Hi again, the relation between Pais and Provincia is just an example, my specific problem is that I have some objects that have M-1 relation with others objects and these also have M-1 relation with others, these relations cause too many accesses to de DataBase. These objects change a lot so I can’t use the cache.

I’m trying to load these M-1 relations in a lazy way, I changed the mappings files to use Lazy=”true”, and with this change I can load Provincias and its Pais doesn’t load, but when I want to see its Pais’s description property, how can I load this object?


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 11:40 am 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
sorry martin,

i guess, if you do not want to add a specific method to build your object graph for each use case, then you should add a generic method to your generic DAO (assuming you have one) that loads a property or object appropriately:

Code:
public void InstantiateLazyProperty(Object obj, string property) {
    PropertyInfo pi = obj.GetType().GetProperty(property);

    if (!NHibernateUtil.IsInitialized(pi)) {
        session.Lock(object, LockMode.None);
        NHibernateUtil.Initialize(pi);
    }
}


-devon


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 12:32 pm 
Beginner
Beginner

Joined: Fri May 12, 2006 10:48 am
Posts: 33
Thank Devon, It’s my first experience on NHibernate and I’m a little confused.
Where do I call the InstantiateLazyProperty function? And when?
Could you send me some code example?

Thank you very much.

Martin


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 2:22 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
martinvicente: did you declare all the public properties and methods of your entities as virtual (overridable)?


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 16, 2006 4:40 pm 
Beginner
Beginner

Joined: Fri May 12, 2006 10:48 am
Posts: 33
I tested it and it worked fine.
Thanks to devonl, Balagan and sergey for your help.
Martin


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