First, I'll describe a little bit the conceptional project, that I'm trying to get working:
There is a database with two schemas, PROD and ARCHIVE and some entity tables in it: TestA, TestB, TestC, TestL. The structure of the tables in both schemas is exactly the same.
TestA has - a many-to-one relation to TestL (lookup table), - a one-to-many relation to TestB, TestB has a one-to-many relation to TestC.
hibernate-prod.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">arcTestDs</property>
<property name="dialect">org.hibernate.dialect.DB2Dialect</property>
<property name="default_schema">PROD</property>
<property name="current_session_context_class">jta</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</property>
<property name="hibernate.transaction.factory_class">com.imd.tracking.arc_test.dao.LocalJtaTransactionFactory</property>
<property name="hibernate.default_schema">PROD</property>
<property name="hibernate.hbm2ddl.auto">validate</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.c3p0.timeout">1000</property>
<property name="show_sql">true</property>
<mapping resource="com/imd/tracking/arc_test/domain/TestADTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestBDTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestCDTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestLDTO.hbm.xml" />
</session-factory>
</hibernate-configuration>
hibernate-arc.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">arcTestDs</property>
<property name="dialect">org.hibernate.dialect.DB2Dialect</property>
<property name="default_schema">ARCHIVE</property>
<property name="current_session_context_class">jta</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup</property>
<property name="hibernate.transaction.factory_class">com.imd.tracking.arc_test.dao.LocalJtaTransactionFactory</property>
<property name="hibernate.default_schema">ARCHIVE</property>
<property name="hibernate.hbm2ddl.auto">validate</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.c3p0.timeout">1000</property>
<property name="show_sql">true</property>
<mapping resource="com/imd/tracking/arc_test/domain/TestADTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestBDTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestCDTO.hbm.xml" />
<mapping resource="com/imd/tracking/arc_test/domain/TestLDTO.hbm.xml" />
</session-factory>
</hibernate-configuration>
TestADTO.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.imd.tracking.arc_test.domain.TestADTO" table="TESTA">
<id column="IDX" name="idx" type="integer">
<generator class="identity" />
</id>
<property column="C1" generated="never" lazy="false" name="c1"
type="string" />
<property column="I1" generated="never" lazy="false" name="i1"
type="integer" />
<many-to-one class="com.imd.tracking.arc_test.domain.TestLDTO"
column="TEXT" fetch="join" name="text" />
<set cascade="all-delete-orphan" inverse="true" lazy="false" name="bs"
sort="unsorted">
<key column="A_IDX" not-null="true" />
<one-to-many class="com.imd.tracking.arc_test.domain.TestBDTO" />
</set>
</class>
</hibernate-mapping>
TestBDTO.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.imd.tracking.arc_test.domain.TestBDTO" table="TESTB">
<id name="idx" type="integer" column="IDX">
<generator class="identity"/>
</id>
<many-to-one fetch="join" name="a" column="A_IDX" class="com.imd.tracking.arc_test.domain.TestADTO" />
<property name="i1" type="integer" column="I1"/>
<property name="i2" type="integer" column="I2"/>
<set name="cs" lazy="false" inverse="true" cascade="all-delete-orphan">
<key column="B_IDX" not-null="true"/>
<one-to-many class="com.imd.tracking.arc_test.domain.TestCDTO"/>
</set>
</class>
</hibernate-mapping>
TestCDTO.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"C://DTDs//hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.imd.tracking.arc_test.domain.TestCDTO" table="TESTC">
<id name="idx" type="integer" column="IDX">
<generator class="identity"/>
</id>
<many-to-one fetch="join" name="b" column="B_IDX" class="com.imd.tracking.arc_test.domain.TestBDTO" />
<property name="i1" type="integer" column="I1"/>
<property name="i2" type="integer" column="I2"/>
</class>
</hibernate-mapping>
TestLDTO.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"C://DTDs//hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.imd.tracking.arc_test.domain.TestLDTO" table="TESTL">
<id name="idx" type="integer" column="IDX">
<generator class="identity"/>
</id>
<property name="text" type="string" >
<column name="TEXT" sql-type="char(20)"/>
</property>
</class>
</hibernate-mapping>
Now, I got two session-factories using a datasource and a jta-transaction-manager.
in my initialization code, I configure the two session-factories with the following code:
sfProd = (SessionFactory)new Configuration()
.configure("/hibernate-prod.cfg.xml")
.setProperty(Environment.DEFAULT_SCHEMA, "PROD")
.buildSessionFactory();
sfArc = (SessionFactory)new Configuration()
.configure("/hibernate-arc.cfg.xml")
.setProperty(Environment.DEFAULT_SCHEMA, "ARCHIVE")
.buildSessionFactory();
Now, i want to select a TestADTO by code like this:
@Transactional
public void moveTest(int moveId)
{
Session s_prod = sfProd.getCurrentSession();
@SuppressWarnings("unchecked")
List<TestADTO> res = (s_prod.createCriteria(TestADTO.class)
.add(Restrictions.idEq(moveId)).list());
TestADTO testA = res.get(0);
// s_prod.evict(testA); // are those lines needed?
// s_prod.evict(testA.getText());
Session s_arc = sfArc.getCurrentSession();
s_arc.save(testA.getText());
s_arc.save(testA);
// later: s_prod.delete(testA);
}
1) if I just run the above code, I get the error
04.02.2016 12:58:03 com.imd.tracking.arc_test.App [main] DEBUG org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:432)
at org.hibernate.event.def.WrapVisitor.processCollection(WrapVisitor.java:67)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
at org.hibernate.event.def.WrapVisitor.processValue(WrapVisitor.java:121)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
at org.hibernate.event.def.AbstractSaveEventListener.visitCollectionsBeforeSave(AbstractSaveEventListener.java:391)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:296)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
at com.imd.tracking.arc_test.dao.Dao.moveTest(Dao.java:161)
at com.imd.tracking.arc_test.dao.Dao$$FastClassByCGLIB$$464493ab.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
at com.imd.tracking.arc_test.dao.Dao$$EnhancerByCGLIB$$dacf9fd6.moveTest(<generated>)
at com.imd.tracking.arc_test.App.go(App.java:106)
at com.imd.tracking.arc_test.App.main(App.java:120)
The exception is thrown when calling s_arc.save(testA.getText());
2) if I detach the dto's with s_prod.evict(testA);
and s_prod.evict(testA.getText());
, I get the error:
org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": com.imd.tracking.arc_test.domain.TestADTO.bs
at org.hibernate.engine.Collections.prepareCollectionForUpdate(Collections.java:248)
at org.hibernate.engine.Collections.processReachableCollection(Collections.java:207)
at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:60)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:84)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:165)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
at org.hibernate.transaction.CacheSynchronization.beforeCompletion(CacheSynchronization.java:88)
at bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent(BitronixTransaction.java:478)
at bitronix.tm.BitronixTransaction.commit(BitronixTransaction.java:193)
at bitronix.tm.BitronixTransactionManager.commit(BitronixTransactionManager.java:120)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1009)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:374)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
at com.imd.tracking.arc_test.dao.Dao$$EnhancerByCGLIB$$359759b9.moveTest(<generated>)
at com.imd.tracking.arc_test.App.go(App.java:106)
at com.imd.tracking.arc_test.App.main(App.java:120)
when leaving the method moveTest(int moveId), I think, the exception is thrown when the transaction is commited.
My goal for the real project is to call a function like moveTest(int moveId) for a list of ids. This should be done in batch process which is planned to be run once a day.
QUESTION: How can I move dtos from one session to another?
P.S.: the real DTOs are having much more relations, so I want to avoid deep copies, if possible.