简体   繁体   中英

Hibernate one-to-many lazy loading with hbm

I have couple of classes, Student and Address . To get one to many relation, let's say that one student can have many addresses. I created .hbm files for this structure, but I want to load addresses for a student lazily. But it is always loading addresses in student object. I can see a couple queries getting fired. Like fetching info from Student table and Address table.

lazy=true or lazy=false doesn't have any effect and 2 queries are always fired (student and address).

Student.hbm:

 <?xml version="1.0"?>
 <!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="hibernate.s4.Student" table="STUDENT">

<id name="studentId" column="stdid">
    <generator class="increment" />
</id>

<property name="studentName" column="stdname" length="10"/>
<property name="phoneno" column="phno" length="10"/>
<property name="degree" column="degree" length="10"/>

<set name="addresses" cascade="save-update" lazy="false">
    <key column="studentId"></key>
    <one-to-many class="hibernate.s4.Address"/>
</set>

</class>
</hibernate-mapping>

Address.hbm:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="hibernate.s4.Address" table="ADDRESS">

<id name="addressid" column="addrid">
    <generator class="increment" />
</id>

<property name="location" column="location" length="10"/>
<property name="area" column="area" length="10"/>
<property name="pin" column="pin" length="6"/>

</class>
</hibernate-mapping>

client class to save data and fetch student object:

Transaction tx = session.beginTransaction();

Student std1 = new Student();
std1.setStudentName("balaji");
std1.setDegree("MCA");
std1.setPhoneno("XXX777CXCC");
session.save(std1);

Address adr1 = new Address();
adr1.setArea("chirala");
adr1.setLocation("AP");
adr1.setPin(523155);
adr1.setStudent(std1);
Address adr3 = new Address();
adr3.setArea("pune");
adr3.setLocation("MH");
adr3.setPin(411028);
adr3.setStudent(std1);
std1.getAddresses().add(adr1);
std1.getAddresses().add(adr3);


System.out.println("Object saved successfully.....!!");
tx.commit();

Query query = session.createQuery("from Student where studentId = :studentId");
query.setParameter("studentId", 1);
List list = query.list();
Student student = (Student)list.get(0);
System.out.println((student.getAddresses() != null ? student.getAddresses().size() : 0 ));

Couple of issues with your code on the println at the end: System.out.println((student.getAddresses() != null ? student.getAddresses().size() : 0 ));

student.getAddresses() won't ever be null because Hibernate uses a proxy object for non-fetched collections. Also calling .size() on your child collection will make hibernate initialize the collection at that point. So it's not null to begin with and by calling .size() you're forcing the collection to be initialized.

Quote from Java Persistence with Hibernate

A proxy is initialized if you call any method that is not the identifier getter method, a collection is initialized if you start iterating through its elements or if you call any of the collection-management operations, such as size() and contains()

You can try setting addresses to lazy="extra" so that when you call .size() it will only fetch the collection size(ie select count(*) from addresses ), not the whole collection itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM