I am having a problem with a self-referencing table and the all-delete-orphan option for a one-to-many list.
If I do any kind of query against this object (other actions also generate the error) within the scope of a transaction, I get the infamous "Don't dereference..." exception. After spending lots of time in the docs, the HIA book, searching the forum, and reading the DereferencedAllDeleteOrphan page, I believe I understand what should generate the exception.
What I don't understand is why it happens in this case :-)
My test case pseudocode:
load the configuration
open a session
start a transaction
do query on nested item
commit transaction
close session
I know I don't need a transaction in this greatly simplified example, but I do have places where I want this behavior (a query within a transaction for the nested object.)
I have tried many combinations of options within the mapping, and it appears that the combination of self-referencing cascading and "all-delete-orphan" is what is messing me up.
It still fails even when none of the 'NestedItem' objects have any children at all (as in my test case).
I am working around it now, but I wonder is whether what I want to do is a bad thing (query within transaction) or if it is a case that just falls outside the scope of the framework.
Thank you for any advice or pointers to what I am doing wrong,
Doug
Hibernate version:
Hibernate 3.0
Mapping documents:
<?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="test">
<class name="NestedItem" table="TEST_NESTED_ITEM">
<id name="nestedItemId" type="integer" column="ID">
<generator class="native"/>
</id>
<property name="name" type="string" column="NAME"/>
<property name="sequence" type="integer" column="SEQUENCE"/>
<many-to-one name="parent" column="PARENT_ID" class="NestedItem" not-null="false"/>
<list name="nestedItems" inverse="true" cascade="all-delete-orphan">
<key column="PARENT_ID"/>
<index column="SEQUENCE"/>
<one-to-many class="NestedItem"/>
</list>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
Code:
Transaction checkTransaction = session.beginTransaction();
List listC = session.createQuery("from NestedItem").list();
int inTXCount = listC.size();
assertEquals("This query should return same count as previous query", checkCount, inTXCount);
log.info("Why is the exception about defererence thrown here?");
checkTransaction.commit();
Full stack trace of any exception that occurs:
org.hibernate.HibernateException: Don't dereference a collection with cascade="all-delete-orphan": test.NestedItem.nestedItems
at org.hibernate.engine.Collections.processDereferencedCollection(Collections.java:70)
at org.hibernate.engine.Collections.processUnreachableCollection(Collections.java:38)
at org.hibernate.event.def.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:211)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:71)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:730)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:324)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at test.BrokenADOTest.testQueryInTransaction(BrokenADOTest.java:60)
Name and version of the database you are using:
HSQLDB 1.7.2
The generated SQL (show_sql=true):
Hibernate: select nesteditem0_.ID as ID, nesteditem0_.NAME as NAME0_, nesteditem0_.SEQUENCE as SEQUENCE0_, nesteditem0_.PARENT_ID as PARENT4_0_ from TEST_NESTED_ITEM nesteditem0_
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Hibernate: select nesteditem0_.ID as ID, nesteditem0_.NAME as NAME0_, nesteditem0_.SEQUENCE as SEQUENCE0_, nesteditem0_.PARENT_ID as PARENT4_0_ from TEST_NESTED_ITEM nesteditem0_
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Hibernate: select nesteditem0_.ID as ID, nesteditem0_.NAME as NAME0_, nesteditem0_.SEQUENCE as SEQUENCE0_, nesteditem0_.PARENT_ID as PARENT4_0_ from TEST_NESTED_ITEM nesteditem0_
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Hibernate: select nesteditem0_.PARENT_ID as PARENT4_1_, nesteditem0_.ID as ID1_, nesteditem0_.SEQUENCE as SEQUENCE1_, nesteditem0_.ID as ID0_, nesteditem0_.NAME as NAME0_0_, nesteditem0_.SEQUENCE as SEQUENCE0_0_, nesteditem0_.PARENT_ID as PARENT4_0_0_ from TEST_NESTED_ITEM nesteditem0_ where nesteditem0_.PARENT_ID=?
Debug level Hibernate log excerpt:
2005-07-01 10:01:23,571 INFO [test.BrokenADOTest.testQueryInTransaction(BrokenADOTest.java:68)] Why is the exception about defererence thrown here?
2005-07-01 10:01:23,581 DEBUG [org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:83)] commit
2005-07-01 10:01:23,581 DEBUG [org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:323)] automatically flushing session
2005-07-01 10:01:23,581 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:52)] flushing session
2005-07-01 10:01:23,581 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:102)] processing flush-time cascades
2005-07-01 10:01:23,581 DEBUG [org.hibernate.engine.Cascades.cascade(Cascades.java:836)] processing cascade ACTION_SAVE_UPDATE for: test.NestedItem
2005-07-01 10:01:23,581 DEBUG [org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:890)] cascade ACTION_SAVE_UPDATE for collection: test.NestedItem.nestedItems
2005-07-01 10:01:23,581 DEBUG [org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:908)] done cascade ACTION_SAVE_UPDATE for collection: test.NestedItem.nestedItems
2005-07-01 10:01:23,581 DEBUG [org.hibernate.engine.Cascades.cascade(Cascades.java:861)] done processing cascade ACTION_SAVE_UPDATE for: test.NestedItem
2005-07-01 10:01:23,591 DEBUG [org.hibernate.engine.Cascades.cascade(Cascades.java:836)] processing cascade ACTION_SAVE_UPDATE for: test.NestedItem
2005-07-01 10:01:23,591 DEBUG [org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:890)] cascade ACTION_SAVE_UPDATE for collection: test.NestedItem.nestedItems
2005-07-01 10:01:23,591 DEBUG [org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:908)] done cascade ACTION_SAVE_UPDATE for collection: test.NestedItem.nestedItems
2005-07-01 10:01:23,591 DEBUG [org.hibernate.engine.Cascades.cascade(Cascades.java:861)] done processing cascade ACTION_SAVE_UPDATE for: test.NestedItem
2005-07-01 10:01:23,591 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener.prepareCollectionFlushes(AbstractFlushingEventListener.java:150)] dirty checking collections
2005-07-01 10:01:23,591 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:167)] Flushing entities and processing referenced collections
2005-07-01 10:01:23,601 DEBUG [org.hibernate.event.def.WrapVisitor.processArrayOrNewCollection(WrapVisitor.java:86)] Wrapped collection in role: test.NestedItem.nestedItems
2005-07-01 10:01:23,601 DEBUG [org.hibernate.engine.Collections.processReachableCollection(Collections.java:140)] Collection found: [test.NestedItem.nestedItems#12], was: [<unreferenced>] (initialized)
2005-07-01 10:01:23,601 DEBUG [org.hibernate.event.def.WrapVisitor.processArrayOrNewCollection(WrapVisitor.java:86)] Wrapped collection in role: test.NestedItem.nestedItems
2005-07-01 10:01:23,601 DEBUG [org.hibernate.engine.Collections.processReachableCollection(Collections.java:140)] Collection found: [test.NestedItem.nestedItems#13], was: [<unreferenced>] (initialized)
2005-07-01 10:01:23,601 DEBUG [org.hibernate.event.def.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:203)] Processing unreferenced collections
2005-07-01 10:01:23,601 DEBUG [org.hibernate.engine.Collections.processDereferencedCollection(Collections.java:50)] Collection dereferenced: [test.NestedItem.nestedItems#12]