-->
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.  [ 8 posts ] 
Author Message
 Post subject: lazy loading one-to-one
PostPosted: Fri Jun 08, 2007 8:07 am 
Newbie

Joined: Tue Mar 13, 2007 6:25 am
Posts: 8
Hi,

I'm having a problem lazy loading a one-to-one association. I'm on NHibernate 1.2. Using the mapping file below, NHibernate is adding the one-to-one class loading into the SQL select statement for the parent class, but is then attempting to fetch it again for each object separately. I don't want it to do either.

mapping files: (snipped for clarity)
Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="DeviceAccess" table="access_history" lazy="true">
    <id name="ID" column="access_id" unsaved-value="0">
      <generator class="native" />
    </id>

    <one-to-one name="Html" class="DeviceAccessHtml" property-ref="accessId"  />
   
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="DeviceAccessHtml" table="access_hist_html" lazy="true">
    <id name="ID" column="html_id" unsaved-value="0">
      <generator class="native" />
    </id>

    <property name="Html" column="html" />
    <property name="accessId" column="access_id" access="field" />

  </class>
</hibernate-mapping>


I've checked there is no code trying to access the one-to-one property. I read a post saying that one-to-ones couldn't be lazy loaded, but then several others stating they could. Can anyone help with the correct setup to get lazy loading?

Cheers
Rory


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 08, 2007 8:48 am 
Newbie

Joined: Tue Mar 13, 2007 6:25 am
Posts: 8
As per the document here: http://www.hibernate.org/162.html, I changed the one-to-one mapping to:
Code:
<one-to-one name="Html" class="DeviceAccessHtml" constrained="true" outer-join="false" />

This causes no loading to occur, however when I then go to access the property I get the exception "NHibernate.ObjectNotFoundException: No row with the given identifier exists: 141013" because the association is on a foreign key. Adding the property-ref attribute back causes a select fetch on the initial load.

So the question now is: how to get lazy load with a one-to-one association on a foreign key?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 08, 2007 5:26 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
From the article above:
Quote:
Right after loading B, you may call getCee() to obtain C. But look, getCee() is a method of YOUR class and Hibernate has no control over it. Hibernate does not know when someone is going to call getCee(). That means Hibernate must put an appropriate value into "cee" property at the moment it loads B from database.

I'm confused here. I thought in NHibernate at least, the proxy for B does know when the setter for Cee is called, because the property must be virtual in your entity class and the proxy overrides it. So, why can't the proxy's override for the Cee property setter attempt to load the value from the database on first access? That way, time won't be wasted on rarely-touched, non-mandatory one-to-one properties.

I seem to remember the answer to a similar question about "why cant a proxy getter/setter initialize something as needed" was "the proxies are generic from Castle, they don't know anything about NHibernate in particular". If that's the case, that's really too bad ...


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 09, 2007 9:00 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
The bottom line is that (N)Hibernate does not support lazy loading of one-to-one relations. There are several posts and explanations on why. There is one post out there by yours truly that says that it's possible and how, but you should ignore it as is was purely the result of a brain-fart in someone who was a novice a the time.

Essentially, if you want to have lazy loading don't use one-to-one, use one-to-many.

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 11, 2007 5:16 am 
Newbie

Joined: Tue Mar 13, 2007 6:25 am
Posts: 8
Thanks for the replies, I came to the same conclusion myself. It is possible if the objects are constrained (there will always be two) but in my case this wasn't always true.

I still had problems with the loading of the object being done in a seperate query, rather than the original object query (this wouldn't be so bad but I could be querying for anything up to a few thousand records). It seems that using property-ref="" on the one-to-one causes it to use another select (despite also adding an outer-join to the original query). In the end I changed the mapping file for the child object to use the foreign key as the identifier, coupling that with an outer-join="true" on the one-to-one mapping got the result I wanted (everything happens in one select).


Top
 Profile  
 
 Post subject: Re: lazy loading one-to-one
PostPosted: Wed May 06, 2009 1:57 am 
Beginner
Beginner

Joined: Wed Aug 22, 2007 5:53 am
Posts: 38
I have the same problem but i can;t remove the property-ref.
Consider this scenatio :
I have one-to-one relation between Product and ProductBasic BUT at database level i have one-to-many between
PRODUCT and PRODUCTBASIC tables as history is mainted in the same table :

PRODUCT ----> PID (PK)
PRODUCTBASIC ---> PID (FK), USECODE , STARTTIMESTAMP forms Composite-key

PRODUCT
PID PNAME
1 Pen

PRODUCTBASIC
PID USECODE STARTTIME ENDTIME
1 100 06-MAY-2009 11:00 07-MAY-2009 10:00
1 100 07-MAY-2009 10:00 31-DEC-9999 00:00

Now while querying for ProductBasic, i will always fetch the row which satisfies the condition STARTTIME<CURRENTTIME<ENDTIME
and this will surely return me only one row.

Ideally the generated sql query should be :

select * from PRODUCT product left outer join PRODUCTBASIC productbasic on '100'=productbasic.USETYPE
and product.PID=productbasic.PID
and (
productbasic.STARTTIME<'09-MAY-2009 10:00'
and '09-MAY-2009 10:00'<productbasic.ENDTIME
)
where
product.PID='1'

PLEASE NOTE, I am not satisfying the relationship by using composite key only, hence i can;t remove property-ref...


Top
 Profile  
 
 Post subject: Re: lazy loading one-to-one
PostPosted: Tue May 26, 2009 8:52 am 
Beginner
Beginner

Joined: Wed Aug 22, 2007 5:53 am
Posts: 38
I have this requirement because i use filter on ProductBasic. and now when this ProductBasic is fetched always (non-lazyly) it doesn't
apply my filter.


Top
 Profile  
 
 Post subject: Re: lazy loading one-to-one
PostPosted: Fri Jan 29, 2010 10:08 am 
Beginner
Beginner

Joined: Fri Jan 23, 2009 10:34 am
Posts: 25
Location: Switzerland
I managed the problem by using @ManyToOne, and avoided the EntityNotFoundException using the workaround described in http://opensource.atlassian.com/project ... e/HHH-2753


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