[
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269?page=c...
]
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....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira