Hello!
I have a trouble using lazy collection loading with cascase refresh
relationship. The collection of objects does not session.refresh correctly
after modification in scope of one session.
Furthermore if i surround session.refresh call with transaction when
Hibernate stores any modifications of collection's objects i have made.
Hibernate version: 3.0
Mapping documents:
Code:
public abstract class DomainObject {
private String _id;
public String getId() {
return _id;
}
private void setId(String id) {
_id = id;
}
}
<class name="Person">
<id name="id">
<generator class="native"/>
</id>
<bag name="passports" lazy="true" cascade="all,delete-orphan">
<key column="personId" not-null="true"/>
<one-to-many class="Passport"/>
</bag>
</class>
public class Person extends DomainObject {
private Collection<Passport> _passports = new ArrayList<Passport>();
public Collection<Passport> getPassports() {
return _passports;
}
public void setPassports(Collection<Passport> passports) {
_passports = passports;
}
}
<class name="Passport">
<id name="id">
<generator class="native"/>
</id>
<property name="firstName"/>
<property name="lastName"/>
</class>
public class Passport extends DomainObject {
private String _firstName;
private String _lastName;
public Passport() {
_firstName = firstName;
_lastName = lastName;
}
public String getFirstName() {
return _firstName;
}
public void setFirstName(String firstName) {
_firstName = firstName;
}
public String getLastName() {
return _lastName;
}
public void setLastName(String lastName) {
_lastName = lastName;
}
}
Code between sessionFactory.openSession() and session.close():Code:
package org.hibernate.test;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class HibernateTest extends TestCase
{
public void testLazy() throws Throwable
{
Transaction tx = null;
Person person = new Person();
Passport passport = new Passport();
passport.setFirstName("Good FirstName");
passport.setLastName("Good LastName");
assertEquals("Good FirstName", passport.getFirstName());
assertEquals("Good LastName", passport.getLastName());
person.getPassports().add(passport);
try
{
tx = getSession().beginTransaction();
getSession().save(person);
assertEquals("Good FirstName", passport.getFirstName());
assertEquals("Good LastName", passport.getLastName());
tx.commit();
}
catch(Throwable e)
{
if(tx != null) tx.rollback();
throw e;
}
try
{
passport = person.getPassports().iterator().next();
passport.setFirstName("Bad FirstName");
passport.setLastName("Bad LastName");
// CASE: transaction on refresh
// tx = getSession().beginTransaction();
// CASE_END: transaction on refresh
getSession().refresh(person);
// CASE: transaction on refresh
//tx.commit();
// CASE_END: transaction on refresh
passport = person.getPassports().iterator().next();
// OK: lazy="false"
// FAILURE: lazy="true"
// FAILURE: lazy="true" with transaction on refresh
assertEquals("Good FirstName", passport.getFirstName());
assertEquals("Good LastName", passport.getLastName());
}
finally
{
tx = getSession().beginTransaction();
getSession().delete(person);
tx.commit();
}
}
private Session getSession()
{
return HibernateSession.getInstance().currentSession();
}
}
Name and version of the database you are using: MS SQLServer 2000 sp3
The generated SQL (show_sql=true):
lazy="false" and lazy="false" with transaction on refresh:
Hibernate: insert into Person default values
Hibernate: insert into Passport (firstName, lastName, PersonID) values (?, ?, ?)
Hibernate: update Passport set PersonID=? where PassportID=?
Hibernate: select person0_.PersonID as PersonID0_ from Person person0_ where person0_.PersonID=?
Hibernate: select passports0_.PersonID as PersonID__, passports0_.PassportID as PassportID__, passports0_.PassportID as PassportID0_, passports0_.firstName as firstName1_0_, passports0_.lastName as lastName1_0_ from Passport passports0_ where passports0_.PersonID=?
Hibernate: select passport0_.PassportID as PassportID0_, passport0_.firstName as firstName1_0_, passport0_.lastName as lastName1_0_ from Passport passport0_ where passport0_.PassportID=?
Hibernate: delete from Passport where PassportID=?
Hibernate: delete from Person where PersonID=?
lazy="true":
Hibernate: insert into Person default values
Hibernate: insert into Passport (firstName, lastName, PersonID) values (?, ?, ?)
Hibernate: update Passport set PersonID=? where PassportID=?
Hibernate: select person0_.PersonID as PersonID0_ from Person person0_ where person0_.PersonID=?
Hibernate: select passports0_.PersonID as PersonID__, passports0_.PassportID as PassportID__, passports0_.PassportID as PassportID0_, passports0_.firstName as firstName1_0_, passports0_.lastName as lastName1_0_ from Passport passports0_ where passports0_.PersonID=?
Hibernate: delete from Passport where PassportID=?
Hibernate: delete from Person where PersonID=?
lazy="true" with transaction on refresh:
Hibernate: insert into Person default values
Hibernate: insert into Passport (firstName, lastName, PersonID) values (?, ?, ?)
Hibernate: update Passport set PersonID=? where PassportID=?
Hibernate: select person0_.PersonID as PersonID0_ from Person person0_ where person0_.PersonID=?
Hibernate: update Passport set firstName=?, lastName=? where PassportID=?
Hibernate: select passports0_.PersonID as PersonID__, passports0_.PassportID as PassportID__, passports0_.PassportID as PassportID0_, passports0_.firstName as firstName1_0_, passports0_.lastName as lastName1_0_ from Passport passports0_ where passports0_.PersonID=?
Hibernate: delete from Passport where PassportID=?
Hibernate: delete from Person where PersonID=?
Debug level Hibernate log excerpt:
10:31:53,638 INFO Environment:460 - Hibernate 3.0
10:31:53,638 INFO Environment:473 - hibernate.properties not found
10:31:53,654 INFO Environment:506 - using CGLIB reflection optimizer
10:31:53,685 INFO Environment:536 - using JDK 1.4 java.sql.Timestamp handling
10:31:53,904 INFO Configuration:1159 - configuring from resource: /hibernate.cfg.xml
10:31:53,935 INFO Configuration:1130 - Configuration resource: /hibernate.cfg.xml
10:31:54,763 INFO Configuration:440 - Mapping resource: org/hibernate/test/Person.hbm.xml
10:31:55,029 INFO HbmBinder:258 - Mapping class: org.hibernate.test.Person -> Person
10:31:55,107 INFO Configuration:440 - Mapping resource: org/hibernate/test/Passport.hbm.xml
10:31:55,216 INFO HbmBinder:258 - Mapping class: org.hibernate.test.Passport -> Passport
10:31:55,232 INFO Configuration:1271 - Configured SessionFactory: null
10:31:55,248 INFO Configuration:851 - processing extends queue
10:31:55,263 INFO Configuration:855 - processing collection mappings
10:31:55,263 INFO HbmBinder:1953 - Mapping collection: org.hibernate.test.Person.passports -> Passport
10:31:55,295 INFO Configuration:864 - processing association property references
10:31:55,295 INFO Configuration:893 - processing foreign key constraints
10:31:55,545 INFO Dialect:91 - Using dialect: org.hibernate.dialect.SQLServerDialect
10:31:55,576 INFO SettingsFactory:90 - Default batch fetch size: 1
10:31:55,591 INFO SettingsFactory:94 - Generate SQL with comments: disabled
10:31:55,607 INFO SettingsFactory:98 - Order SQL updates by primary key: disabled
10:31:55,607 INFO SettingsFactory:273 - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
10:31:55,638 INFO ASTQueryTranslatorFactory:21 - Using ASTQueryTranslatorFactory
10:31:55,638 INFO SettingsFactory:106 - Query language substitutions: {}
10:31:55,670 INFO DriverManagerConnectionProvider:41 - Using Hibernate built-in connection pool (not for production use!)
10:31:55,670 INFO DriverManagerConnectionProvider:42 - Hibernate connection pool size: 20
10:31:55,685 INFO DriverManagerConnectionProvider:45 - autocommit mode: false
10:31:55,701 INFO DriverManagerConnectionProvider:80 - using driver: net.sourceforge.jtds.jdbc.Driver at URL: jdbc:jtds:sqlserver://localhost/jupiter_backup
10:31:55,716 INFO DriverManagerConnectionProvider:86 - connection properties: {user=jupiter, password=****}
10:31:56,076 INFO SettingsFactory:156 - Scrollable result sets: enabled
10:31:56,076 INFO SettingsFactory:164 - JDBC3 getGeneratedKeys(): enabled
10:31:56,091 INFO TransactionFactoryFactory:31 - Using default transaction strategy (direct JDBC transactions)
10:31:56,107 INFO TransactionManagerLookupFactory:33 - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
10:31:56,138 INFO SettingsFactory:176 - Automatic flush during beforeCompletion(): disabled
10:31:56,154 INFO SettingsFactory:179 - Automatic session close at end of transaction: disabled
10:31:56,154 INFO SettingsFactory:260 - Cache provider: org.hibernate.cache.EhCacheProvider
10:31:56,185 INFO SettingsFactory:187 - Second-level cache: enabled
10:31:56,185 INFO SettingsFactory:192 - Optimize cache for minimal puts: disabled
10:31:56,201 INFO SettingsFactory:199 - Structured second-level cache entries: enabled
10:31:56,216 INFO SettingsFactory:203 - Query cache: disabled
10:31:56,232 INFO SettingsFactory:210 - Echoing all SQL to stdout
10:31:56,232 INFO SettingsFactory:214 - Statistics: disabled
10:31:56,248 INFO SettingsFactory:218 - Deleted entity synthetic identifier rollback: disabled
10:31:56,263 INFO SettingsFactory:232 - Default entity-mode: pojo
10:31:56,529 INFO SessionFactoryImpl:140 - building session factory
10:31:56,591 WARN Configurator:126 - No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/D:/projects/hibernate_test/server/lib/ehcache-1.1.jar!/ehcache-failsafe.xml
10:31:57,591 INFO SessionFactoryObjectFactory:82 - Not binding factory to JNDI, no JNDI name configured
10:31:57,591 INFO SessionFactoryImpl:366 - Checking 0 named queries