I have a basic parent / child relationship, as in chapter 21 of the Hibernate reference book.
Cascade - only from child to parent (keep the cascade only because I do not want to remove the parent if I delete the child).
When I add a child to the parent element and I save it, I have a TransientObjectException ...
@Entity public class Parent implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @OneToMany(mappedBy = "parent", orphanRemoval = true) private List<Child> childs; public List<Child> getChilds() { return childs; } public void setChilds(List<Child> childs) { this.childs = childs; } public void addChild(Child child) { if (childs == null) childs = new ArrayList<Child>(); if (childs.add(child)) child.setParent(this); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } } @Entity public class Child implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne(optional = false) @Cascade( { PERSIST, MERGE, REFRESH, SAVE_UPDATE, REPLICATE, LOCK, DETACH }) private Parent parent; public Parent getParent() { return parent; } public void setParent(Parent parent) { this.parent = parent; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } } @Test public void test() { Parent parent = new Parent(); Child child = new Child(); parent.addChild(child); genericDao.saveOrUpdate(child); }
But on saveOrUpdate, I have this exception:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Child at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244) at org.hibernate.collection.AbstractPersistentCollection.getOrphans(AbstractPersistentCollection.java:911) at org.hibernate.collection.PersistentBag.getOrphans(PersistentBag.java:143) at org.hibernate.engine.CollectionEntry.getOrphans(CollectionEntry.java:373) at org.hibernate.engine.Cascade.deleteOrphans(Cascade.java:471) at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:455) at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362) at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338) at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) at org.hibernate.engine.Cascade.cascade(Cascade.java:161) at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:476) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:354) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677) at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669) at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252) at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392) at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335) at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) at org.hibernate.engine.Cascade.cascade(Cascade.java:161) at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:451) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:677) at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:669) at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:665)
I really don't understand, because saving a child should save a parent through a cascade ... Any ideas?
UPDATE 1
The problem seems to be related to "orphanRemoval", because if I comment on its parent:
@OneToMany(mappedBy = "parent" /*, orphanRemoval = true */) private List<Child> childs;
It works!
He saves the child, then the parent.
But I really need the orphan to be removed through the cascade when I remove the child from its parent.
UPDATE 2
I created a JIRA problem:
http://opensource.atlassian.com/projects/hibernate/browse/HHH-5364
UPDATE 3
Seems fixed :-)
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2269
java hibernate orphan one-to-many cascade
Cedric thiebault
source share