Hibernate version:
Hibernate 3.2CR1, Hibernate Annotations 3.1 beta 9, Hibernate Entity Manager 3.1 beta7
Full stack trace of any exception that occurs:
When persisting a group object that references a detached user object the following error occurs.
Code:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: test.PersistMergeTest$User
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:562)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:193)
at test.PersistMergeTest.persist(PersistMergeTest.java:59)
at test.PersistMergeTest.testPersistObjectWithDetachedObjectReference(PersistMergeTest.java:158)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: test.PersistMergeTest$User
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:79)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:608)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:600)
at org.hibernate.engine.CascadingAction$8.cascade(CascadingAction.java:202)
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.cascadeCollectionElements(Cascade.java:290)
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:121)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:38)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:617)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:591)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:595)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:187)
... 17 more
Name and version of the database you are using:MySQL 5.0.20
TestCaseCode:
package test;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Persistence;
import junit.framework.TestCase;
import org.hibernate.annotations.GenericGenerator;
public class PersistMergeTest extends TestCase
{
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");;
@Entity
static class User
{
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
String id;
@ManyToOne(optional = true, fetch = FetchType.EAGER)
Group group;
}
@Entity
static class Group
{
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
String id;
@OneToMany(mappedBy = "group", fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.REFRESH})
Set<User> users = new HashSet<User>();
}
private void persist(Object e) throws RuntimeException
{
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try
{
tx = em.getTransaction();
tx.begin();
em.persist(e);
tx.commit();
}
catch (RuntimeException ex)
{
if (tx != null && tx.isActive()) tx.rollback();
throw ex;
}
finally
{
em.close();
}
}
private void merge(Object e) throws RuntimeException
{
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try
{
tx = em.getTransaction();
tx.begin();
em.merge(e);
tx.commit();
}
catch (RuntimeException ex)
{
if (tx != null && tx.isActive()) tx.rollback();
throw ex;
}
finally
{
em.close();
}
}
/* FAILS */
public void testPersistObjectWithDetachedObjectReference()
{
// instantiate and persist a user object
User aUser = new User();
persist(aUser);
assertNotNull(aUser.id);
// instantiate a group object
Group aGroup = new Group();
// assign the detached user object to the new group object
aGroup.users.add(aUser);
aUser.group = aGroup;
// **************************************
// the following statement will throw javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: test.UserEntity
// **************************************
persist(aGroup);
}
/* WORKS */
public void testMergeObjectWithDetachedObjectReference()
{
// instantiate and persist a user object
User aUser = new User();
persist(aUser);
assertNotNull(aUser.id);
// instantiate and persist a group object
Group aGroup = new Group();
persist(aGroup);
assertNotNull(aGroup.id);
// assign the user to the group and merge the group object
aGroup.users.add(aUser);
aUser.group = aGroup;
merge(aGroup);
}
}
Is this the expected behaviour?
Any help is appreciated.
Regards, Johan