-->
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.  [ 15 posts ] 
Author Message
 Post subject: Hibernate Lazy Load not working correctly
PostPosted: Thu Jul 26, 2007 9:39 am 
Newbie

Joined: Thu Jun 21, 2007 9:32 am
Posts: 5
Hey all. I couldn't find anything dealing with this topic on here yet so hopefully someone can help me out and tell me what I am doing wrong.

I have four Java classes that are representations of the various entries that will be stored in the DB through Hibernate. Below is a described example of how the classes are related.

"There can be many Class C objects in one Class B object. There can be many Class B objects in one Class A object. Class A also has a reference to Class D, which is bi-directional."

I am attempting to use hibernates lazy load method to only load up the singleton object of Class A, however the issue I am running into is that it is not working as advertised. My understanding is that when you load an object from the DB into memory, the *-to-one relationships get proxies loaded for them that hold only the identifier values (In my above example, when i load Class A, a proxy is loaded for Class D and for the Class B list). The problem I am facing is that it isn't loading only the proxies, but actually going through and loading the objects from the DB. I know this because I turned on the show_sql and use_sql_comments tags for hibernate and I can see that it is calling the get* methods I wrote for them.

So in a nutshell, what is happening is that when I load up Class A, it also loads up Class D, loads each entry for Class B, and then for each entry in Class B it loads the Class C list. Rather than gunk up this forum with more info than you all need, let me know what files you would like to see and I will place them up here to assist you in helping me solve this problem. I look forward to your reply.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 10:28 am 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Perhaps start with the sections of the mapping files that define the relationships between your classes.

I just built a basic example mirroring the scenario you described and I get the expected lazy loading behaviour.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 10:32 am 
Expert
Expert

Joined: Fri Aug 19, 2005 2:11 pm
Posts: 628
Location: Cincinnati
classA mapping data, how you're loading classA.

What are these get* methods you wrote for classB and class D?

_________________
Chris

If you were at work doing this voluntarily, imagine what you'd want to see to answer a question.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 11:41 am 
Newbie

Joined: Thu Jun 21, 2007 9:32 am
Posts: 5
Class Mapping for Class A
Code:
<hibernate-mapping>
    <class name="test.ClassA" table="TBLCLASSA">
        <id name="classAId">
            <column name="classAId"></column>
        </id>
        <property name="name" type="string" not-null="false"/>
        <many-to-one name="classD" class="test.ClassD" cascade="none" lazy="proxy" fetch="join">
            <column name="classA"></column>
        </many-to-one>
        <bag name="ClassBList" lazy="true" inverse="true" cascade="none">
            <key column="classAId"/>
            <one-to-many class="test.ClassB"/>
        </bag>
    </class>
</hibernate-mapping>


GetAllCLassA method: Used to get all instances of Class A:

Code:
//getClassB is used to give the user the option to get the Class B listing for the element from the DB. Currently i pass in false as it's value.
public ArrayList<ClassA> getAllClassA(boolean getClassB){
    Query q = null;
    ArrayList<ClassA> listing = null;

    //This session variable is global and the method is abstract. It just gets the current session.
    session = getSession();
    try{
        q = session.createQuery("from ClassA");
        listing = (ArrayList<ClassA>) q.list();
        //Currently this if statement is commented out in my code, so it shouldn't be implemented at all no matter the value of getClassB.
        if(getClassB){
            for(ClassA a : listing){
                a.getClassBListSize();
            }
        }
    }
    catch(Exception e){
        closeSession();
        e.printStackTrace();
    }

    return listing;
}


And just in case, the ClassA.java:

Code:
package test;

public class ClassA{
    private ClassD classD;
    private ArrayList<ClassB> classBList = new ArrayList<ClassB>();
    private String name;

    public ClassA(){
    }

    public void setClassD(ClassD classD){
        this.classD = classD;
    }

    public ClassD getClassD(){
        return classD;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setClassBList(ArrayList<ClassB> classBList){
        this.classBList = classBList;
    }

    public ArrayList<ClassB> getClassBList(){
        return classBList;
    }

    public int getClassBListSize(){
        return classBList.size();
    }

}


I think this is everything you all asked for... i will double check and if not i will edit the posting.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 12:39 pm 
Expert
Expert

Joined: Fri Aug 19, 2005 2:11 pm
Posts: 628
Location: Cincinnati
your mapping and load methods are ok and it should only be loading proxies. I'm curious why you say it's calling your B and D load methods. Double check the logs and make sure it's not performing how you say.

Check to see if the data is there in the collection. If you try to access one of its collections (B or D) outsiide the session it should give you an exception.

_________________
Chris

If you were at work doing this voluntarily, imagine what you'd want to see to answer a question.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 1:52 pm 
Newbie

Joined: Thu Jun 21, 2007 9:32 am
Posts: 5
I was definitely able to access ClassB's id value without any issue, so the data is in fact being loaded up and I have no idea why when all the things are set to lazily load.

One other thing that might be relavent, might not: I am populating the ClassA's material from a view of another DB. This means I am not generating the ID, more just setting it and then saving that info to my DB. I don't honestly see how this could be a big issue for the loading of the material, but I am curious if it might be relavent in some way.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 26, 2007 2:00 pm 
Expert
Expert

Joined: Fri Aug 19, 2005 2:11 pm
Posts: 628
Location: Cincinnati
try loading a specific one and see if that changes what happens.

do a session.load(Class, Serializable ID); call

_________________
Chris

If you were at work doing this voluntarily, imagine what you'd want to see to answer a question.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 27, 2007 5:19 am 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Quote:
I was definitely able to access ClassB's id value without any issue, so the data is in fact being loaded up and I have no idea why when all the things are set to lazily load.


If you're inside the same session, accessing ClassB's id value will cause hibernate to fetch the ClassB entities from the database. Perhaps this is what you're seeing.

I notice that your getAllClassA method only closes the session when an exception occurs so perhaps the session is still active. Is this really what you want?

With your example code in a simple test case everything worked as expected. ClassB's were only loaded when getClassB was true.

On a general note, with the Collections API you should really use the interface types for everything except instantiating a new Collection.

e.g.
public ArrayList<ClassA> getAllClassA(boolean getClassB)
Should be
public List<ClassA> getAllClassA(boolean getClassB)

e.g.
public class ClassA{
private ArrayList<ClassB> classBList = new ArrayList<ClassB>();
Should be
public class ClassA{
private List<ClassB> classBList = new ArrayList<ClassB>();

I got a hibernate error because of this when trying to run your example code:
expected type: java.util.ArrayList,
actual value: org.hibernate.collection.PersistentBag


Top
 Profile  
 
 Post subject: Lazyload of Map using Hibernate Annotations only.
PostPosted: Fri Jul 27, 2007 5:53 am 
Newbie

Joined: Fri Jul 27, 2007 5:48 am
Posts: 8
Can any one please help me with Lazyload of Map objects of Java using Hibernate Annotations only?

My piece of code -

@CollectionOfElements
@OneToOne(fetch = FetchType.LAZY)
@MapKey(columns = { @Column(name = "locale", nullable = false)})
private Map values;

Instead of @OneToOne, I also tried with
@LazyCollection(LazyCollectionOption.TRUE)

But Unable to lazy load the map.

Moreover the mapping file used in Hibernate are automatically generated. I can't write them explicitly.

Regards,
Sucheta.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 27, 2007 6:22 am 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Hi Sucheta
Although on a related subject, you should open a new post for your query rather than tagging this onto the end of an existing post. Its the way the forum should work _and_ you're more likely to get help this way.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 27, 2007 7:13 am 
Newbie

Joined: Thu Jun 21, 2007 9:32 am
Posts: 5
thatmikewilliams wrote:
If you're inside the same session, accessing ClassB's id value will cause hibernate to fetch the ClassB entities from the database. Perhaps this is what you're seeing.


No, what happens is I have show_sql turned on, and when I call my getAllClassA method even though the Class B is set to be lazily loaded i see in the sql calls made it is making a call to get the Class B, Class C, and Class D values. It goes all the way down the tree.

thatmikewilliams wrote:
I notice that your getAllClassA method only closes the session when an exception occurs so perhaps the session is still active. Is this really what you want?


This was just a Copy and Paste error on my part, it closes inside the try when everything is completed.


So the issue still remains. Can someone possibly shed light on how fetching works with Hibernate? I read up on some website that it needs to have a generated key to fetch correctly or something along those lines... since my Class A's ID is just copied over from a different DB to keep consistency, could this be an issue as to why I am not getting the expected results?


Top
 Profile  
 
 Post subject: Hey
PostPosted: Fri Jul 27, 2007 7:29 am 
Newbie

Joined: Fri Jul 27, 2007 5:48 am
Posts: 8
Hey,
Thanks for your suggestion.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 27, 2007 7:39 am 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Quote:
it needs to have a generated key to fetch correctly

I'm using your sample code with assigned IDs (rather than generated) and lazy loading is working fine so this isn't the issue.

Perhaps you could try turning on hibernate's debug logging and examine what's happening around ClassA load time.

Create the simplest test case and see if that works as expected.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 27, 2007 7:39 am 
Newbie

Joined: Thu Jun 21, 2007 9:32 am
Posts: 5
Just a bump so that it doesn't look like the last message made this resolved. It is still an issue. Read my previous post for details, thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 02, 2007 12:40 am 
Newbie

Joined: Mon May 08, 2006 1:01 pm
Posts: 5
Any word on this issue? i seem to be having the same problem.

thanks.


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