Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: LazyInitializationException executing a HQL in Eclipse
PostPosted: Tue Feb 14, 2006 3:12 pm 
Beginner
Beginner

Joined: Mon Nov 28, 2005 11:03 am
Posts: 39
Location: Madrid
Dear members,

I get a LazyInitializationException, executing a simple query like this:
select c from Country as c

where I have defined the Country table like this:

Quote:
CREATE TABLE country (
country_id VARCHAR(3) NOT NULL
, name VARCHAR(40) NOT NULL
, PRIMARY KEY (country_id)
);

and the table shareholder as a foreing key to Country, like this:

Quote:
CREATE TABLE shareholder (
shareholder_id INT(11) UNSIGNED NOT NULL IDENTITY PRIMARY KEY
, NIF VARCHAR(10)
, name VARCHAR(80) NOT NULL
, last_name VARCHAR(40)
, type INT(2) UNSIGNED NOT NULL
, citizenship VARCHAR(3)
, is_resident BOOL
, is_credit_entity BOOL
, CONSTRAINT fk_shareholder_1 FOREIGN KEY (citizenship)
REFERENCES country (country_id)
, CONSTRAINT fk_shareholder_2 FOREIGN KEY (type)
REFERENCES shareholder_type (shareholder_type_id)
);


The hbm mapping files are:

Quote:
<hibernate-mapping>
<class name="com.schinvest.lra.domain.Country" table="country">
<id name="id" type="string">
<column name="country_id" length="3" />

<generator class="assigned" />
</id>

<property name="name" type="string">
<column name="name" length="40" not-null="true" />
</property>

<set name="shareholders" inverse="true">
<key>
<column name="citizenship" length="3" />
</key>

<one-to-many class="com.schinvest.lra.domain.Shareholder" />
</set>

<set name="contracts" inverse="true">
<key>
<column name="country_id" length="3" />
</key>

<one-to-many class="com.schinvest.lra.domain.Contract" />
</set>
</class>
</hibernate-mapping>

and

Quote:
hibernate-mapping>
<class name="com.schinvest.lra.domain.Shareholder" table="shareholder">
<id name="id" type="int">
<column name="shareholder_id" />

<generator class="assigned" />
</id>

<many-to-one name="shareholderType" class="com.schinvest.lra.domain.ShareholderType" fetch="select">
<column name="type" not-null="true" />
</many-to-one>

<many-to-one name="country" class="com.schinvest.lra.domain.Country" fetch="select">
<column name="citizenship" length="3" />
</many-to-one>

<property name="nif" type="string">
<column name="NIF" length="10" />
</property>

<property name="name" type="string">
<column name="name" length="80" not-null="true" />
</property>

<property name="lastName" type="string">
<column name="last_name" length="40" />
</property>

<property name="isResident" type="java.lang.Boolean">
<column name="is_resident" />
</property>

<property name="isCreditEntity" type="java.lang.Boolean">
<column name="is_credit_entity" />
</property>

<set name="contractShareholders" inverse="true">
<key>
<column name="shareholder_id" not-null="true" />
</key>

<one-to-many class="com.schinvest.lra.domain.ContractShareholder" />
</set>
</class>
</hibernate-mapping>


The log files says:

Code:
!ENTRY org.eclipse.jface 4 2 2006-02-14 20:04:36.890
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.jface".
!STACK 0
org.hibernate.LazyInitializationException: illegal access to loading collection....


I suspect it is a problem with the association between Country and Shareholders for examples, but I don't see the reason why?

I have seen another post about the Lazy initialization, but I didn't found a real solution for this common problem.

On the Country generated class I have a method like this: Set getShareholders(){} and on the Shareholder class a method like this:
Country getContry(){}

┬┐Please could you tell me what I am doing wrong?

The *.hbm.xml files where generated using hibernate tool (latest beta version)

Thanks in advance,

David Leal

_________________
David Leal


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 2:51 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8611
Location: Neuchatel, Switzerland (Danish)
the full stacktrace probably reveals that your domain code is doing bad things in equals/hashcode.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 2:42 pm 
Beginner
Beginner

Joined: Mon Nov 28, 2005 11:03 am
Posts: 39
Location: Madrid
Max,

Thanks again for your input, looking on the stack trace there is a information about the hashcode, but I don't know what I am doing wrong.

The stack trace revels that:

Code:
   at com.schinvest.lra.domain.ShareholderType.hashCode(ShareholderType.java:104)
   at com.schinvest.lra.domain.ShareholderType$$FastClassByCGLIB$$a5768f5c.invoke(<generated>)
   at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
   at org.hibernate.proxy.CGLIBLazyInitializer.intercept(CGLIBLazyInitializer.java:161)
   at com.schinvest.lra.domain.ShareholderType$$EnhancerByCGLIB$$d726e0d2.hashCode(<generated>)
   at com.schinvest.lra.domain.Shareholder.hashCode(Shareholder.java:176)
   at java.util.HashMap.hash(HashMap.java:264)
   at java.util.HashMap.put(HashMap.java:382)
   at java.util.HashSet.add(HashSet.java:194)
   at java.util.AbstractCollection.addAll(AbstractCollection.java:318)


so it fails invoking the ShareholderType.hashCode(), but why?, the hashcode and equals are generated by Hibernate Tools. In each case I have:

For ShareholderType:

Code:
public int hashCode() {
         int result = 17;
         
         result = 37 * result + this.getId();
         result = 37 * result + ( getName() == null ? 0 : this.getName().hashCode() );
         result = 37 * result + ( getShareholders() == null ? 0 : this.getShareholders().hashCode() ); LINE 104!!!!!         
return result;
   }   


and for Shareholder:

Code:
public int hashCode() {
         int result = 17;
         
         result = 37 * result + this.getId();
         result = 37 * result + ( getShareholderType() == null ? 0 : this.getShareholderType().hashCode() ); LINE 176!!!!         result = 37 * result + ( getCountry() == null ? 0 : this.getCountry().hashCode() );
         result = 37 * result + ( getNif() == null ? 0 : this.getNif().hashCode() );
         result = 37 * result + ( getName() == null ? 0 : this.getName().hashCode() );
         result = 37 * result + ( getLastName() == null ? 0 : this.getLastName().hashCode() );
         result = 37 * result + ( getIsResident() == null ? 0 : this.getIsResident().hashCode() );
         result = 37 * result + ( getIsCreditEntity() == null ? 0 : this.getIsCreditEntity().hashCode() );
         result = 37 * result + ( getContractShareholders() == null ? 0 : this.getContractShareholders().hashCode() );
         return result;
   }   


The table definition for ShareholderType is:

Code:
CREATE TABLE shareholder_type (
       shareholder_type_id INT(2) UNSIGNED NOT NULL IDENTITY PRIMARY KEY
     , name VARCHAR(10) NOT NULL
);


and I have inserted the following values:
Code:
INSERT INTO shareholder_type (shareholder_type_id, name) VALUES ('1', 'F');
INSERT INTO shareholder_type (shareholder_type_id, name) VALUES ('2', 'J');


The *.hbm.xml file for ShareholderType is:

Code:
<hibernate-mapping>
    <class name="com.schinvest.lra.domain.ShareholderType" table="shareholder_type">
        <meta attribute="class-description">Plain old Java object that maps onto the shareholder_type table. &lt;br&gt; It was auto-generated on Feb 15, 2006 7:17:33 PM by
        Hibernate Tools 3.1.0.beta4.</meta>

        <meta attribute="use-in-tostring">true</meta>

        <meta attribute="use-in-equals">true</meta>

        <id name="id" type="int">
            <column name="shareholder_type_id" />

            <generator class="assigned" />
        </id>

        <property name="name" type="string">
            <column name="name" length="10" not-null="true" />
        </property>

        <set name="shareholders" inverse="true">
            <key>
                <column name="type" not-null="true" />
            </key>

            <one-to-many class="com.schinvest.lra.domain.Shareholder" />
        </set>
    </class>
</hibernate-mapping>


Please could you tell me where is the mistery about lazy initialization exception?, :-)

Thanks in advance,

David Leal

_________________
David Leal


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 15, 2006 3:01 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8611
Location: Neuchatel, Switzerland (Danish)
yes, dont enabled use-in-equals on collections!

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Problem Solved
PostPosted: Thu Feb 16, 2006 7:47 am 
Beginner
Beginner

Joined: Mon Nov 28, 2005 11:03 am
Posts: 39
Location: Madrid
Max,

Thanks again, just to add one comment more for other people with the same problem. After solving the equal/hashcode problem you can get an Overflow Exception because a similar reason because the toString method implementation using the meta tag:

Code:
<meta attribute="use-in-tostring">true</meta>


The problem is the same, if you have Shareholder and ShareholderType related because the inverse = "true", the toString method of one class needs the information about the other class of the relationship, so you have to decide where to put the information on the association, but not in both side.

So by default this meta tag hibernate tool will the attribute information in both sides:

on Shareholder.java:

Code:
buffer.append("shareholderType").append("='").append(getShareholderType()).append("' ");


and on the ShareholderType.java

Code:
      buffer.append("shareholders").append("='").append(getshareholders()).append("' ");


wich is a circular dependence and therfore produce overflow.

So you have to decide on which side of the association you wanto the information into toString. My recomendation is to avoid a general <meta> tag information on the *.hbm.xml file, and add by hand on one direction of the association, for example:

Shareholder.hbm.xml:

without the toString meta attribute.

Code:
<many-to-one name="shareholderType" class="com.schinvest.lra.domain.ShareholderType" fetch="select">
            <meta attribute="use-in-tostring">true</meta>
            <column name="type" not-null="true" />
        </many-to-one>


and on the ShareholderType.hbm.xml:

Code:
<set name="shareholders" inverse="true">
            <key>
                <column name="type" not-null="true" />
            </key>

            <one-to-many class="com.schinvest.lra.domain.Shareholder" />
        </set>


Thank again for you precise help like always,

David Leal

_________________
David Leal


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 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.