I have been trying to lazy load some collections in my entity, which are usually loaded by default. The Criteria API offers a setFetchMode(FetchMode.LAZY) option, but it doesn't seem to work the way I expect it to. Below is a test which replicates the problem.
I do not want to use a lazy="true" on the mapping, as the real entity is used in many different places which require it to be fully loaded. This is the exception.
Hibernate version:2.1.6
Mapping documents:
Code:
<hibernate-configuration>
<session-factory name="SessionFactory">
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@myServer:1521:SID</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password">pwd</property>
<!-- END TEST_CONFIG -->
<property name="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</property>
<property name="hibernate.show_sql">false</property>
<property name="hibernate.session_factory_name"></property>
<mapping resource="spike/hibernate/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Code:
<hibernate-mapping>
<class name="spike.hibernate.Person" table="person">
<id column="id" type="long" access="field" name="id">
<generator class="increment"/>
</id>
<property name="name" column="first_name" access="field" />
<bag name="addresses" access="field" table="address" >
<key>
<column name="person_id"/>
</key>
<composite-element class="spike.hibernate.Address">
<property access="field" name="id" column="id"/>
<property access="field" name="address" column="address"/>
</composite-element>
</bag>
</class>
</hibernate-mapping>
TestCode:
public class LazyCriteriaTest extends TestCase {
private Session session;
private SessionFactory sessionFactory;
protected void setUp() throws Exception {
Configuration configuration = new Configuration();
configuration.configure("/hibernate.cfg.xml");
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
}
public void testLazyLoadingDoesNotInitialiseTheLazyCollection() throws Exception {
Transaction transaction = session.beginTransaction();
Person person = createPerson();
session.save(person);
transaction.commit();
session.close();
session = sessionFactory.openSession();
Person fetched =
(Person) session.createCriteria(Person.class).
setFetchMode("addresses", FetchMode.LAZY).
add(Expression.eq("id", person.id)).
uniqueResult();
assertFalse("Should not have initialised the collection.", Hibernate.isInitialized(fetched.addresses));
}
private Person createPerson() {
List addresses = new ArrayList();
addresses.add(new Address("my address", new Long(1)));
addresses.add(new Address("his address", new Long(2)));
Person person = new Person("Chris", addresses);
return person;
}
}
Code:
public class Person {
String name;
Long id;
List addresses;
public Person() {
}
public Person(String name, List addresses) {
this.name = name;
this.addresses = addresses;
}
}
Code:
public class Address {
String address;
Long id;
public Address() {
}
public Address(String address, Long id) {
this.address = address;
this.id = id;
}
}
Result:Code:
junit.framework.AssertionFailedError: Should not have initialised the collection.
at spike.hibernate.LazyCriteriaTest.testLazyLoadingDoesNotInitialiseTheLazyCollection(LazyCriteriaTest.java:36)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:78)
Any suggestions gratefully received. If this is a genuine bug, please let me know, as I have had to patch it locally to meet performance requirements ... regards, Chris Tarttelin