I am having an issue with a persistent collection becoming unreferenced when all-delete-orphan is set. For the life of me I can't figure out how the collection becomes unreferenced. All I do is to create 3 elements and save them in the database then, from a different session, read the collection. Calling session.flush() after the initial save reaps the same results.
Can anyone shed any light as to what criteria Hibernate uses to determine when a collection is unreferenced and how we could go about convincing it that our collection is perfectly fine?
Hibernate version: 3.2.6
Mapping documents:
Code:
<set name="permanentFeatures" cascade="all-delete-orphan" inverse="false" lazy="false">
<key column="CRASH_ID" not-null="true"/>
<one-to-many class="com.rta.crashlink.feature.PermanentFeature"/>
</set>
Code between sessionFactory.openSession() and session.close():(edited for relevance)
Note that this is a groovy test case but that the Java method calls are the same
HibernateTemplate obtains a session and provides it in the session variable
Code:
def crashId
new HibernateTemplate(null).doInSession({session ->
crashDao.setSession(session)
permanentFeatureDao.setSession(session)
PermanentFeatureCode featureCode1 = permanentFeatureDao.findByCodeValue(1L)
PermanentFeatureCode featureCode2 = permanentFeatureDao.findByCodeValue(2L)
PermanentFeatureCode featureCode3 = permanentFeatureDao.findByCodeValue(3L)
PermanentFeature feature1 = new PermanentFeature()
PermanentFeature feature2 = new PermanentFeature()
PermanentFeature feature3 = new PermanentFeature()
feature1.feature = featureCode1
feature2.feature = featureCode2
feature3.feature = featureCode3
assertEquals("Wrong Feature Code", 1L, feature1.feature.code)
assertEquals("Wrong Feature Code", 2L, feature2.feature.code)
assertEquals("Wrong Feature Code", 3L, feature3.feature.code)
Crash crash = new Crash()
def newFeatures = new HashSet()
newFeatures << feature1
newFeatures << feature2
newFeatures << feature3
assertEquals("Wrong set size", 3, newFeatures.size())
crash.setPermanentFeatures(newFeatures)
crashDao.save(crash)
//crashDao.flush()
crashId = crash.crashId
assertNotNull(crashId)
assertEquals("Wrong number of features", 3, crash.permanentFeatures.size())
},false)
def sql = Sql.newInstance(
"jdbc:oracle:thin:@XXXXXXXXXXXXX",
"XXXXXXXX",
"XXXXXXX",
"oracle.jdbc.OracleDriver")
def row = sql.firstRow("select count(*) as num from XXXXXXX where CRASH_ID = ${crashId}")
assertEquals("Wrong number of features in database", 3, (int) (row.num))
new HibernateTemplate(null).doInSession({session ->
crashDao.setSession(session)
permanentFeatureDao.setSession(session)
Crash crash = crashDao.findById(crashId)
assertNotNull("Crash not found", crash)
def features = crash.permanentFeatures
},false)
Full stack trace of any exception that occurs:Code:
org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.rta.crashlink.crash.Crash.permanentFeatures
at org.hibernate.engine.Collections.processDereferencedCollection(Collections.java:96)
at org.hibernate.engine.Collections.processUnreachableCollection(Collections.java:39)
at org.hibernate.event.def.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:218)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:77)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:95)
at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke(MetaClassHelper.java:599)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:904)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:740)
at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:761)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:749)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:167)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:195)
at com.rta.crashlink.test.hibernate.HibernateTemplate.doInSession(HibernateTemplate.groovy:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:95)
at org.codehaus.groovy.runtime.MetaClassHelper.doMethodInvoke(MetaClassHelper.java:599)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:904)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:740)
at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:773)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:753)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:167)
at com.rta.crashlink.crash.CrashDAOHibernateTest.testReplacePermanentFeatures(CrashDAOHibernateTest.groovy:134)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:76)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Name and version of the database you are using:Oracle 10g
The generated SQL (show_sql=true):Code:
select
permanentf0_.CRASH_ID as CRASH8_2_,
permanentf0_.CRA_FEAT_ID as CRA1_2_,
permanentf0_.CRA_FEAT_ID as CRA1_188_1_,
permanentf0_.CRASH_ID as CRASH8_188_1_,
permanentf0_.CREATED_BY as CREATED2_188_1_,
permanentf0_.CREATED_DT as CREATED3_188_1_,
permanentf0_.MODIFIED_BY as MODIFIED4_188_1_,
permanentf0_.MODIFIED_DT as MODIFIED5_188_1_,
permanentf0_.PRIMARY_YN as PRIMARY6_188_1_,
permanentf0_.CRA_FEAT_TIMESTAMP as CRA7_188_1_,
permanentf0_.CRA_PERMFEAT_ID as CRA9_188_1_,
permanentf1_.CRA_LKP_CODE as CRA1_149_0_,
permanentf1_.CREATED_BY as CREATED2_149_0_,
permanentf1_.CREATED_DT as CREATED3_149_0_,
permanentf1_.CRA_LKP_DESC as CRA4_149_0_,
permanentf1_.CRA_LKP_LDESC as CRA5_149_0_,
permanentf1_.MODIFIED_BY as MODIFIED6_149_0_,
permanentf1_.MODIFIED_DT as MODIFIED7_149_0_,
permanentf1_.CRA_LKP_SHDESC as CRA8_149_0_,
permanentf1_.STATUS_FLAG as STATUS9_149_0_,
permanentf1_.CRA_LKP_SUBHEAD_CODE as CRA10_149_0_,
permanentf1_.CRA_LKP_SUBHEAD_DESC as CRA11_149_0_,
permanentf1_.CRA_LKP_SRC as CRA12_149_0_
from
CRSHLNK2.BSE_PERMFEAT permanentf0_
left outer join
CRSHLNK2.LKP_CRA_PERMFEAT permanentf1_
on permanentf0_.CRA_PERMFEAT_ID=permanentf1_.CRA_LKP_CODE
where
permanentf0_.CRASH_ID=?
Debug level Hibernate log excerpt:Code:
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.transaction.JDBCTransaction - commit
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.impl.SessionImpl - automatically flushing session
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.AbstractFlushingEventListener - flushing session
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.rta.crashlink.crash.Crash
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.trafficUnits
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.trafficUnits
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.notes
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.notes
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.permanentFeatures
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [com.rta.crashlink.feature.PermanentFeature#327]
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,658] main org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [com.rta.crashlink.feature.PermanentFeature#328]
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.AbstractSaveEventListener - persistent instance of: com.rta.crashlink.feature.PermanentFeature
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - ignoring persistent instance
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.DefaultSaveOrUpdateEventListener - object already associated with session: [com.rta.crashlink.feature.PermanentFeature#329]
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.permanentFeatures
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.temporaryFeatures
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.Cascade - done cascade ACTION_SAVE_UPDATE for collection: com.rta.crashlink.crash.Crash.temporaryFeatures
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.rta.crashlink.crash.Crash
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.AbstractFlushingEventListener - Flushing entities and processing referenced collections
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.WrapVisitor - Wrapped collection in role: com.rta.crashlink.crash.Crash.permanentFeatures
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.event.def.WrapVisitor - Wrapped collection in role: com.rta.crashlink.crash.Crash.temporaryFeatures
DEBUG [2008-07-23 15:24:13,673] main org.hibernate.engine.Collections - Collection found: [com.rta.crashlink.crash.Crash.trafficUnits#232], was: [com.rta.crashlink.crash.Crash.trafficUnits#232] (uninitialized)
DEBUG [2008-07-23 15:24:13,689] main org.hibernate.engine.Collections - Collection found: [com.rta.crashlink.crash.Crash.notes#232], was: [com.rta.crashlink.crash.Crash.notes#232] (uninitialized)
DEBUG [2008-07-23 15:24:13,689] main org.hibernate.engine.Collections - Collection found: [com.rta.crashlink.crash.Crash.permanentFeatures#232], was: [<unreferenced>] (initialized)
DEBUG [2008-07-23 15:24:13,689] main org.hibernate.engine.Collections - Collection found: [com.rta.crashlink.crash.Crash.temporaryFeatures#232], was: [<unreferenced>] (initialized)
DEBUG [2008-07-23 15:24:13,689] main org.hibernate.event.def.AbstractFlushingEventListener - Processing unreferenced collections
DEBUG [2008-07-23 15:24:13,689] main org.hibernate.engine.Collections - Collection dereferenced: [com.rta.crashlink.crash.Crash.permanentFeatures#232]