-->
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: Working with Entity Relationships
PostPosted: Mon May 10, 2010 2:13 pm 
Beginner
Beginner

Joined: Mon May 10, 2010 2:00 pm
Posts: 22
I am getting the infamous LazyInitializationException in a simple web app I am writing.

I have 2 entities being access: Person and Report

Here is the Person Java Class:
Code:
package dao.entity;
// Generated May 6, 2010 2:28:45 PM by Hibernate Tools 3.2.1.GA


import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
* Person generated by hbm2java
*/
public class Person  implements java.io.Serializable {


     private int personId;
     private String fullName;
     private Date lastLogin;
     private Set<Report> reports = new HashSet<Report>(0);

    public Person() {
    }

   
    public Person(int personId) {
        this.personId = personId;
    }
    public Person(int personId, String fullName, Date lastLogin, Set<Report> reports) {
       this.personId = personId;
       this.fullName = fullName;
       this.lastLogin = lastLogin;
       this.reports = reports;
    }
   
    public int getPersonId() {
        return this.personId;
    }
   
    public void setPersonId(int personId) {
        this.personId = personId;
    }
    public String getFullName() {
        return this.fullName;
    }
   
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    public Date getLastLogin() {
        return this.lastLogin;
    }
   
    public void setLastLogin(Date lastLogin) {
        this.lastLogin = lastLogin;
    }
    public Set<Report> getReports() {
        return this.reports;
    }
   
    public void setReports(Set<Report> reports) {
        this.reports = reports;
    }

}


And here is the Hibernate Mapping File:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated May 6, 2010 2:28:51 PM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
    <class name="dao.entity.Person" table="PERSON" schema="busn0110ridPm1" lazy="false" >
        <id name="personId" type="int">
            <column name="PERSON_ID" precision="9" scale="0" />
            <generator class="increment" />
        </id>
        <property name="fullName" type="string">
            <column name="FULL_NAME" length="300" />
        </property>
        <property name="lastLogin" type="date">
            <column name="LAST_LOGIN" length="7" />
        </property>
        <set name="reports" inverse="true">
            <key>
                <column name="PERSON_ID" precision="9" scale="0" />
            </key>
            <one-to-many class="dwd.dao.entity.Report" />
        </set>
    </class>
</hibernate-mapping>


Here is the Report Java Class:
Code:
package dao.entity;
// Generated May 6, 2010 2:28:45 PM by Hibernate Tools 3.2.1.GA


import java.util.Date;

/**
* Report generated by hbm2java
*/
public class Report  implements java.io.Serializable {


     private int reportId;
     private Project project;
     private Person person;
     private Date dateSubmitted;
     private String pageUrl;
     private String message;
     private String status;
     private String expectedResults;
     private String developer_notes;

    public Report() {
    }

    public Report(int reportId) {
        this.reportId = reportId;
    }
    public Report(int reportId, Project project, Person person, Date dateSubmitted, String pageUrl, String message, String status) {
       this.reportId = reportId;
       this.project = project;
       this.person = person;
       this.dateSubmitted = dateSubmitted;
       this.pageUrl = pageUrl;
       this.message = message;
       this.status = status;
    }

    public String getDeveloper_notes() {
        return developer_notes;
    }

    public void setDeveloper_notes(String developer_notes) {
        this.developer_notes = developer_notes;
    }

    public String getExpectedResults() {
        return expectedResults;
    }

    public void setExpectedResults(String expectedResults) {
        this.expectedResults = expectedResults;
    }
   
    public int getReportId() {
        return this.reportId;
    }
   
    public void setReportId(int reportId) {
        this.reportId = reportId;
    }
    public Project getProject() {
        return this.project;
    }
   
    public void setProject(Project project) {
        this.project = project;
    }
    public Person getPerson() {
        return this.person;
    }
   
    public void setPerson(Person person) {
        this.person = person;
    }
    public Date getDateSubmitted() {
        return this.dateSubmitted;
    }
   
    public void setDateSubmitted(Date dateSubmitted) {
        this.dateSubmitted = dateSubmitted;
    }
    public String getPageUrl() {
        return this.pageUrl;
    }
   
    public void setPageUrl(String pageUrl) {
        this.pageUrl = pageUrl;
    }
    public String getMessage() {
        return this.message;
    }
   
    public void setMessage(String message) {
        this.message = message;
    }
    public String getStatus() {
        return this.status;
    }
   
    public void setStatus(String status) {
        this.status = status;
    }

}


And the Report Hibernate Mapping File:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated May 6, 2010 2:28:51 PM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
    <class name="dao.entity.Report" table="REPORT" schema="busn0110ridPm1" lazy="false">
        <id name="reportId" type="int">
            <column name="REPORT_ID" precision="9" scale="0" />
            <generator class="increment" />
        </id>
        <many-to-one name="project" class="dwd.dao.entity.Project" fetch="select">
            <column name="PROJECT_ID" precision="9" scale="0" />
        </many-to-one>
        <many-to-one name="person" class="dwd.dao.entity.Person" fetch="select">
            <column name="PERSON_ID" precision="9" scale="0" />
        </many-to-one>
        <property name="dateSubmitted" type="date">
            <column name="DATE_SUBMITTED" length="7" />
        </property>
        <property name="pageUrl" type="string">
            <column name="PAGE_URL" length="1000" />
        </property>
        <property name="message" type="string">
            <column name="MESSAGE" length="0" />
        </property>
        <property name="status" type="string">
            <column name="STATUS" length="500" />
        </property>
        <property name="expectedResults" type="string">
            <column name="EXPECTED_RESULTS" length="4000" />
        </property>
        <property name="developer_notes" type="string">
            <column name="DEVELOPER_NOTES" length="4000" />
        </property>
    </class>
</hibernate-mapping>



I have a Data Access Object set up to handle my Hibernate functions. Here are the portions of the file that I am using for this particular feature:
Code:
...
public ArrayList getReportsByProjectId(int project_id) {
     String hql = "from Report where project_id=" + project_id;
     return getObjects(hql);
}

public ArrayList getObjects(String hql) {
        ArrayList list = new ArrayList();

        try {
            session = getSession();
            trans = session.beginTransaction();
            list = (ArrayList) session.createQuery(hql).list();
            trans.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeSession(session);
        }

        return list;
    }
...


In my page controller I grab the reports by the project_id and loop through them to display on the page. When I attempt to access the Person data it fails and gives me the LazyInitializationException.

From this information can anybody help me understand the proper HQL or Java syntax that populates the Person within the Report records I am retrieving? I guess I assumed that Hibernate automatically fetched that data from the Person table when I did the call for the reports. After all I am getting the person_id out of the Person object...

Any help with this would be greatly appreciated.

Thanks


Top
 Profile  
 
 Post subject: Re: Working with Entity Relationships
PostPosted: Mon May 10, 2010 3:22 pm 
Newbie

Joined: Mon May 10, 2010 1:41 pm
Posts: 15
You say:
list = (ArrayList) session.createQuery(hql).list();

This may not be an issue but,
.list() returns List not ArrayList... have you verified that the backing class is ArrayList? Even if you have it is good to follow the contract.

public ArrayList getReportsByProjectId(int project_id)
aught to be:
public List<Report> getReportsByProjectId(int project_id)


Top
 Profile  
 
 Post subject: Re: Working with Entity Relationships
PostPosted: Tue May 11, 2010 9:00 am 
Beginner
Beginner

Joined: Mon May 10, 2010 2:00 pm
Posts: 22
Thanks! :) I'm not well versed in that syntax, but I'll research and implement it into my code.

Question about that syntax: I want to have a reusable function for returning a list of objects. How would I pass the object class into the function for applying to the List? Here is what I am currently using:

Code:
public ArrayList getObjects(String hql) {
        ArrayList list = new ArrayList();

        try {
            session = getSession();
            trans = session.beginTransaction();
            list = (ArrayList) session.createQuery(hql).list();
            trans.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeSession(session);
        }

        return list;
    }


Any clue of how to resolve my Lazy Loading issue with Hibernate?


Top
 Profile  
 
 Post subject: Re: Working with Entity Relationships
PostPosted: Tue May 11, 2010 12:34 pm 
Newbie

Joined: Mon May 10, 2010 1:41 pm
Posts: 15
Really I don't know much about Hibernate... but... you should work with the return type, unless you know for a fact what backs it.
Here let's change this method so it agrees with the contract:

public List getObjects(String hql) {
List list = null; //here you created an arraylist, but never used it... actually it gets thrown away... when you did the assignment.

try {
session = getSession();
trans = session.beginTransaction();
list = session.createQuery(hql).list(); //here list() returns a new List so list would have a new reference
trans.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSession(session);
}
return list;
}
/* so now list either contains a good list or null, but it would never contain null... unless an exception was thrown (because you would get an empty list otherwise)... The better way is throwing the exception rather than checking for null. Say this is a web application, you would want some error condition set and some error message set which the web page could display.*/

Understanding Generics: This is really simple and I recommend using this syntax for a while until you get used to it...
You are comfortable with the type ArrayList... and you know that an ArrayList can hold any type of Objects. But more often than not your program does not expect a particular ArrayList to hold anytype of object... So instead of just saying plain old ArrayList we say ArrayList<Report> and if we want to be clear in cases where we know the ArrayList could hold different types of Objects we could say ArrayList<?>. Say the ArrayList isn't holding any random object but objects that share a base class we could enforce this with ArrayList<? extends Report>, now our list will only hold Reports, TSPReports and TopSecretReports or what ever extends Report. So you get the idea. If your method returns ArrayList<?> (as in the case with getObjects() because it could return a few different kinds) then when it gets to a method that is designed to process a certain type of Object, say Report Objects then you can cast ArrayList<?> to ArrayList<Report> and you are good to go.

Why do this: 1) It makes it easier to read because it is clear without looking around what is coming and going from containers. 2) It will help catch errors, because it is more difficult to use the container incorrectly.

Here is the above method again with Generics:
public List<?> getObjects(String hql) {
List<?> list = null; //here you created an arraylist, but never used it... actually it gets thrown away... when you did the assignment.

try {
session = getSession();
trans = session.beginTransaction();
list = session.createQuery(hql).list(); //here list() returns a new List so list would have a new reference
trans.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSession(session);
}
return list;
}

PS: I didn't test any of the code.


Top
 Profile  
 
 Post subject: Re: Working with Entity Relationships
PostPosted: Thu May 13, 2010 2:17 pm 
Beginner
Beginner

Joined: Mon May 10, 2010 2:00 pm
Posts: 22
Well... what I have found on my own so far is that I need to load the Person objects into the Reports before closing the Hibernate Session. I may eventually write a reusable method that can handle this for any class, but for now I'll handle these types of request in a way similar to what I have done with the Report object.

Here is one of the method for retrieving the Report objects that clears up the Lazy load:

Code:
public ArrayList getReportsByProjectIdWithSort(int project_id, String sortby) {
        String hql = "from Report where project_id=" + project_id + " order by " + sortby;
        // The List<Report> object will get the Reports from Hibernate       
        List<Report> report_list = null;
        // The ArrayList<Report> will contain the modified Report objects and will be returned by this method
        ArrayList<Report> list = new ArrayList<Report>();
        try {
            session = getSession();
            trans = session.beginTransaction();
            report_list = session.createQuery(hql).list();
            for (int i = 0; i < report_list.size(); i++) {
                Report report = report_list.get(i);
                // Here I load the Person and Project objects while the Hibernate Session/Transaction is still open
                Person person = getPersonByPersonId(report.getPerson().getPersonId());
                Project project = getProjectByProjectId(report.getProject().getProjectId());
                // I overwrite the Report.Person and Report.Project with the objects I've explicitly loaded
                report.setPerson(person);
                report.setProject(project);
                list.add(report);
            }
        } catch (Exception e) {
            Util.printError(e);
        } finally {
            closeSession(session);
        }
        return list;
    }


I doubt this is the most efficient way to do this, but it does work consistently without errors.


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.