[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2269) Many-to-one cascade fails with TransientObjectException if the inverse collection is marked CascadeType.DELETE_ORPHAN
Gail Badner (JIRA)
noreply at atlassian.com
Fri Oct 19 14:11:39 EDT 2007
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_28493 ]
Gail Badner commented on HHH-2269:
----------------------------------
This issue reproduces when running BidirectionalOneToManyCascadeTest.testSaveOrphanDeleteChildWithParentFailureExpected() on HSQLDB and MySQL databases. There was no problem when using Oracle 10g.
Because the "native" ID generator is used for this test, an identity is used for ID fields for HSQLDB and MySQL, and a sequence is used for Oracle.
While debugging, I can see that ForeignKeys.getContextEntityIdentifier() returns null when using HSQLDB and MySQL, but returns the actual ID when using Oracle. The null ID later causes the TransientObjectException.
The difference in behavior is because the ID is not available until after the entity is inserted when an identity is used. When a sequence is used, the ID can be obtained before the insert.
> Many-to-one cascade fails with TransientObjectException if the inverse collection is marked CascadeType.DELETE_ORPHAN
> ---------------------------------------------------------------------------------------------------------------------
>
> Key: HHH-2269
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
> Project: Hibernate3
> Issue Type: Bug
> Components: core
> Affects Versions: 3.2.0.cr2, 3.2.1
> Environment: Using hibernate annotations.
> Reporter: Edward Costello
> Attachments: new-testcase.tgz, TestBidirectionalCascade.java
>
>
> When both a many-to-one (child) and it's inverse one-to-many collection (on parent) are cascading. Attempting to save a child directly and cascade the save to the parent throws a TransientObjectException if the parent's collection is mapped CascadeType.DELETE_ORPHAN. For Example, with the classes below:
> @Entity
> public class Parent {
> @OneToMany(mappedBy = "parent")
> @Cascade(value = {CascadeType.ALL, CascadeType.DELETE_ORPHAN})
> Set<DeleteOrphanChild> deleteOrphanChildren;
> }
> @Entity
> public class DeleteOrphanChild {
> @ManyToOne
> @Cascade(value = CascadeType.ALL)
> Parent parent;
> }
> Calling session.save() with an instance of the parent will cascade the save to the child as expected. However, calling save on an instance of the child will throw the TransientObjectException below while attempting to cascade the save to the parent.
> org.hibernate.TransientObjectException: cascade.test.TestBidirectionalCascade$DeleteOrphanChild
> at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:216)
> at org.hibernate.collection.AbstractPersistentCollection.getOrphans(AbstractPersistentCollection.java:889)
> at org.hibernate.collection.PersistentSet.getOrphans(PersistentSet.java:51)
> at org.hibernate.engine.CollectionEntry.getOrphans(CollectionEntry.java:350)
> at org.hibernate.engine.Cascade.deleteOrphans(Cascade.java:336)
> at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:318)
> at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:185)
> at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:160)
> at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
> at org.hibernate.engine.Cascade.cascade(Cascade.java:248)
> at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:437)
> at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:326)
> at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
> at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
> at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:509)
> at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:501)
> at org.hibernate.engine.CascadingAction$1.cascade(CascadingAction.java:134)
> at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:213)
> at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:157)
> at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
> at org.hibernate.engine.Cascade.cascade(Cascade.java:248)
> at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
> at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
> at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
> at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
> at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
> at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
> at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
> at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:537)
> at org.hibernate.impl.SessionImpl.save(SessionImpl.java:525)
> at org.hibernate.impl.SessionImpl.save(SessionImpl.java:521)
> If the DELETE_ORPHAN cascade is removed the save works fine. The attached test case runs against an in memory HSQLDB database. It contains 4 tests, the second test (testSaveChildDeleteOrphan) fails showing the above exception. The other three pass showing that cascading from the parent works and that cascading in both directions remove if the DELETE_ORPHAN cascade is removed.
> We've only tested this with annotations, we haven't tried to reproduce it using hibernate mapping files.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
More information about the hibernate-issues
mailing list