I am trying to understand the behavior of hibernate (yep, I'm a newbie), and I'm trying to understand the following situation.
I have a class (Person) that has a one to many association with another class (Address). I have turned off lazy loading and am watching the generated SQL to understand how hibernate loads information from the database. In addition, I have explicitly set fetch="join" on the association to tell hibernate I would like to use an outer join to fetch information on the associated classes.
When I use session.load(), the generated SQL is what I would expect -- a single select created using an outer join. However using HQL (from Person p), hibernate does N+1 selects to get the information.
Is there something I have to change in my configuration to get a single select, or is this just standard behavior for hibernate? Any other tips you could give me on how these mappings should be written would greatly be appreciated as well. I apologize if this is a somewhat stupid question, but, as I said, I'm new. (
Hibernate In Action is on its way ;)).
Hibernate version:
3.05
Mapping documents:
Person.hbm.xml:
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">
<hibernate-mapping package="net.vickerscraven.learning.hibernate">
<class name="Person" table="person">
<id name="id" column="per_id" unsaved-value="null">
<generator class="native"/>
</id>
<property name="firstName" column="per_first_name" not-null="true"/>
<property name="lastName" column="per_last_name" not-null="true"/>
<property name="birthDate" column="per_birth_date" not-null="true"/>
<property name="weightInKilograms" column="per_weight_kg" not-null="true"/>
<property name="heightInMeters" column="per_height_m" not-null="true"/>
<set name="addresses" lazy="false" inverse="true" fetch="join">
<key column="per_id"/>
<one-to-many class="Address"/>
</set>
</class>
</hibernate-mapping>
Address.hbm.xml:
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">
<hibernate-mapping package="net.vickerscraven.learning.hibernate">
<class name="Address" table="address">
<composite-id>
<key-many-to-one name="owner" class="Person" column="per_id"/>
<key-property name="tag" column="tag"/>
</composite-id>
<property name="address" column="address" not-null="true"/>
<property name="address2" column="address2" not-null="false"/>
<property name="city" column="city" not-null="true"/>
<property name="state" column="state" not-null="true"/>
<property name="zip" column="zip"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
person = (Person)session.load(Person.class, new Integer(1));
System.out.println(person.getFirstName() + " " + person.getLastName());
Query q = session.createQuery("from Person p");
List results = q.list();
System.out.println(results.size() + " result(s) found.");
Iterator iter = results.iterator();
while (iter.hasNext()) {
person = (Person)iter.next();
System.out.println(person.getFirstName() + " " + person.getLastName());
addresses = person.getAddresses();
addressIter = addresses.iterator();
System.out.println(person.getFirstName() + " has " + addresses.size() + " associated addresses:");
while (addressIter.hasNext()) {
address = (Address)addressIter.next();
System.out.println(address.getTag());
}
}
Name and version of the database you are using:PostgreSQL 8
The generated SQL (show_sql=true): (all program output)
Code:
Hibernate: select person0_.per_id as per1_1_, person0_.per_first_name as per2_1_1_, person0_.per_last_name as per3_1_1_, person0_.per_birth_date as per4_1_1_, person0_.per_weight_kg as per5_1_1_, person0_.per_height_m as per6_1_1_, addresses1_.per_id as per1_3_, addresses1_.tag as tag3_, addresses1_.per_id as per1_0_, addresses1_.tag as tag0_, addresses1_.address as address0_0_, addresses1_.address2 as address4_0_0_, addresses1_.city as city0_0_, addresses1_.state as state0_0_, addresses1_.zip as zip0_0_ from person person0_ left outer join address addresses1_ on person0_.per_id=addresses1_.per_id where person0_.per_id=?
Aaron Craven
Hibernate: select person0_.per_id as per1_, person0_.per_first_name as per2_1_, person0_.per_last_name as per3_1_, person0_.per_birth_date as per4_1_, person0_.per_weight_kg as per5_1_, person0_.per_height_m as per6_1_ from person person0_
Hibernate: select addresses0_.per_id as per1_1_, addresses0_.tag as tag1_, addresses0_.per_id as per1_0_, addresses0_.tag as tag0_, addresses0_.address as address0_0_, addresses0_.address2 as address4_0_0_, addresses0_.city as city0_0_, addresses0_.state as state0_0_, addresses0_.zip as zip0_0_ from address addresses0_ where addresses0_.per_id=?
Hibernate: select addresses0_.per_id as per1_1_, addresses0_.tag as tag1_, addresses0_.per_id as per1_0_, addresses0_.tag as tag0_, addresses0_.address as address0_0_, addresses0_.address2 as address4_0_0_, addresses0_.city as city0_0_, addresses0_.state as state0_0_, addresses0_.zip as zip0_0_ from address addresses0_ where addresses0_.per_id=?
Hibernate: select addresses0_.per_id as per1_1_, addresses0_.tag as tag1_, addresses0_.per_id as per1_0_, addresses0_.tag as tag0_, addresses0_.address as address0_0_, addresses0_.address2 as address4_0_0_, addresses0_.city as city0_0_, addresses0_.state as state0_0_, addresses0_.zip as zip0_0_ from address addresses0_ where addresses0_.per_id=?
Hibernate: select addresses0_.per_id as per1_1_, addresses0_.tag as tag1_, addresses0_.per_id as per1_0_, addresses0_.tag as tag0_, addresses0_.address as address0_0_, addresses0_.address2 as address4_0_0_, addresses0_.city as city0_0_, addresses0_.state as state0_0_, addresses0_.zip as zip0_0_ from address addresses0_ where addresses0_.per_id=?
5 result(s) found.
Aaron Craven
Aaron has 1 associated addresses:
home
Christopher Craven
Christopher has 0 associated addresses:
Kleetus Vickers
Kleetus has 0 associated addresses:
John Smith
John has 0 associated addresses:
Katrina Craven
Katrina has 0 associated addresses: