We're updating the issue view to help you get more done. 

PersistentObjectException: detached entity passed to persist when using EmbeddedId

Description

I have three entities: Person, City and PersonCity. The PersonCity entity is a mapped M:N table between Peron and City which uses an @EmbeddedId as the primary key attribute. The other entities, Person and City, both use a @OneToMany as a reference back to PersonCity. The mapping of the M:N table is required to store additional information about an association.

1 2 3 4 5 6 7 8 9 10 11 12 @Entity public class City { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "city") private Set<PersonCity> personCitySet = new HashSet<>(); //... }
1 2 3 4 5 6 7 8 9 10 11 12 @Entity public class Person { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true) private Set<PersonCity> personCitySet = new HashSet<>(); // ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Entity public class PersonCity { @EmbeddedId private PersonCityKey id = new PersonCityKey(); @ManyToOne @MapsId("personId") private Person person; @ManyToOne @MapsId("cityId") private City city; private String additionalInfo; // .... }
1 2 3 4 5 6 7 8 9 10 11 12 @Embeddable public class PersonCityKey implements Serializable { private Long personId; private Long cityId; public PersonCityKey() { } // ... }

First I create a City and a Person and connect them via a PersonCity entity. Then I start a new transaction, load the created City using a LoadGraph and detach it immediatelly. That detach causes a PersistentObjectException when the transaction gets committed.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:75) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71) at org.hibernate.bugs.JPAUnitTestCase.causesPersistentObjectException(JPAUnitTestCase.java:92) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.junit.runner.JUnitCore.run(JUnitCore.java:160) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: org.hibernate.bugs.test.City at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:56) ... 26 more Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: org.hibernate.bugs.test.City at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:840) at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:833) at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:341) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126) at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:150) at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:141) at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:74) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38) at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1435) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68) ... 25 more

The exception doesn't get thrown when I comment out the call to EntityManager.detach. Debugging into the Hibernate code reveals, that Hibernate tries to persist the City entity which is referenced by the previously created (and already persisted) PersonCity object. It cascades a persist operation through PersonCity.city even though there is no cascade specified on the @ManyToOne reference. Moreover, I'm no sure if that persist is really required in that situation.

Environment

java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)

Hibernate Version: 5.2.10.Final

Database (Test): H2 1.4.196

Status

Assignee

Unassigned

Reporter

Andreas Kilian

Fix versions

None

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

5.2.10

Priority

Major