[hibernate-issues] [Hibernate-JIRA] Created: (HHH-2269) Many-to-one cascade fails with TransientObjectException if the inverse collection is marked CascadeType.DELETE_ORPHAN

Edward Costello (JIRA) noreply at atlassian.com
Tue Nov 28 16:08:04 EST 2006


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
        Type: Bug

  Components: core  
    Versions: 3.2.0.cr2, 3.2.1    
 Environment: Using hibernate annotations.
    Reporter: Edward Costello
 Attachments: 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