-->
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.  [ 5 posts ] 
Author Message
 Post subject: Lazy Instantiation of Child's Children
PostPosted: Mon Jun 05, 2006 5:06 pm 
Newbie

Joined: Mon Jun 05, 2006 4:53 pm
Posts: 4
I have 3 tables I am using to test NHibernate. For the most part, things work, but I'm having a heck of a time with lazy instantiation.

Simple structure is: User has many Notes which have many Comments.

By default, all relations have lazy="true". This works fine. Now, when I want to select all Users and their notes, I set fetch mode="JOIN" on the criteria, and do the select. This works fine to get the Notes. However, I cannot get both the Notes and the Comments in one fetch. If I set the Notes and Comments lasy="false" everything works fine, but that won't scale past my testing.


crit.SetFetchMode("Notes", FetchMode.Join)
crit.SetFetchMode("Notes.Comments", FetchMode.Join)

' Iterate through users here
' Iterate through user.notes here...
' Iterate through note.Comments here <-- Throws error.

I'm using VB.Net, so all methods are virtual, so that isn't the problem. Am I missing something here?




Code:
   
    <class name="HibernateTest.PersistedUser, HibernateTest" table="PUser">
        <id name="UserId" column="user_id" type="Int32">
            <generator class="native" />
        </id>
        <property name="Username" column="username" type="String" length="255"/>
        <property name="Email"    column="email"    type="String" length="255"/>
       
        <set name="Notes" table="PNote" order-by="note_id" lazy="true">
         <key column="user_id"/>
         <one-to-many class="HibernateTest.Note, HibernateTest"/>
      </set>
    </class>

    <class name="HibernateTest.Note, HibernateTest" table="PNote">
        <id name="NoteId" column="note_id" type="Int32">
            <generator class="native" />
        </id>
        <property name="UserId" column="user_id" type="Int32"/>
        <property name="Text"    column="note_text"    type="String" length="255"/>
       
        <set name="Comments" table="PComment" order-by="comment_id" lazy="true">
         <key column="note_id"/>
         <one-to-many class="HibernateTest.Comment, HibernateTest"/>
      </set>
      
    </class>

    <class name="HibernateTest.Comment, HibernateTest" table="PComment">
        <id name="CommentId" column="comment_id" type="Int32">
            <generator class="native" />
        </id>
        <property name="NoteId" column="note_id" type="Int32"/>
        <property name="UserId" column="user_id" type="Int32"/>
        <property name="Text"    column="note_text"    type="String" length="255"/>
    </class>



Any additional pointers are appreciated.

-S


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 06, 2006 8:45 am 
Newbie

Joined: Mon Jun 05, 2006 4:53 pm
Posts: 4
So to clarify:
- Using NHibernate 1.0.2.0
- Given a Grandparent / Parent / Child table structure where all mappings specify lazy="true":

I want to do something with the Grandparent and Parent here, so I do the following (pseudocode):
Code:
  //  create session and transaction here
  c = session.CreateCriteria( System.Type.GetType( GrandParent ) )
  c.SetFetchMode( "Parents", FetchMode.Join )
  grandparents = c.List()
  //  close session and transaction here
 
  //  Do things here with Grandparent and Parent, and all is well.



Now I want to do something with the Grandparent, Parent, and Child, so I try something similar:
Code:
  //  create session and transaction here
  c = session.CreateCriteria( System.Type.GetType( GrandParent ) )
  c.SetFetchMode( "Parents", FetchMode.Join )
  c.SetFetchMode( "Parents.Children", FetchMode.Join )
  grandparents = c.List()
  //  close session and transaction here
 
  //  Do things with records here...
  //    work with grandparent successful
  //    work with parents successful
  //    work with children -> NHibernate.LazyInitializationException



So is there a way to tell a criteria to load specific collections down the tree heirarchy along with the initial query? Or am I stuck needing to manually fetch each of the child records by calling their accessors prior to closing the session?

According to the documentation, SetFetchMode accepts a dot seperated property path, so it seems like my above query should work. Is there any reason you can see that it wouldn't?

Thanks for your time.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 06, 2006 11:09 am 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
you might be running into a limitation of NH. From the Hibernate in Action book:

Quote:
Hibernate currently limits you to fetching just one colleciton eagerly.


i am currently running into the same issue in some instances and have been wondering about changing the global fetch depth to something other than 1 like maybe 3 (which would help you too). have you tried that at all? i'm specifically talking about the hibernate.max_fetch_depth property.

-devon


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 06, 2006 11:42 am 
Newbie

Joined: Mon Jun 05, 2006 4:53 pm
Posts: 4
Thanks for the response, Devon. Changing that property per your suggestion did not seem to have any affect on the behavior of my application, however.


So if I am out of luck loading all the relations at once, is there a more efficient way to load all the children manually short of looping through the collections and accessing their properties manually? Is this how you are addressing it in the locations that you are experiencing it?


Since if I set lazy=false for the relationships they will load any number of collections to any depth, I don't understand the limitation being imposed when I am working with the records in this manner.


-S


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 06, 2006 12:01 pm 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
currently, i have been setting lazy="false" and enabling the second-level cache on the objects and collections to get around my problem. But for my particular situation, this is actually a preferred method. As an example, a key part of my app is the Survey with a collection of Questions, each with a Collection of Answer options. these surveys are basically static (once they are finished being created) so caching the Survey with read-write is fine for me.

setting the Survey.Question and Question.Answers collection to lazy=false also works well because 80% of the time i need access to those collections when i reference the Survey object. it comes in even more handy when it comes to storing a Members survey answers. i end up having Member.MemberSurvey.Answers.Question. i usually load the MemberSurvey object directly so I end up with a MemberSurvey.Answers lazily-loaded collection that, once loaded can also find Answer.Question.Answers if i need to for reporting features.

i am hoping one of the veterans can stop by and help out with this question though because i think there must be a better way alalagous to what you have tried. in the HiA book, they often state that all relationships should be lazy (and in the next version of NH that will be the default) and that you should be using HQL to load a fully-populated object graph for each use case. so... let's see it 'cuz i haven't figured it out yet.


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