Hibernate 3.6.6.Final (JBoss 6.1) merge() transient object tree

384 Views Asked by At

I try to save an object tree with Hibernate's merge() method. Entity Auftrag (means "order" in English) contains a collection of Auftragsposition objects, mapped with cascade="all-delete-orphan.

The persisting occurs in a stateless session bean, called via RMI. The method opens a new (clean) Session instance. When an already existing order is saved, merge() tries to load the entity from the DB and in turn associates the just loaded dependent order positions with the session's persistence context. Later on, when the merge() operation is cascaded upon the order positions, a NonUniqueObjectException occurs (because the transient order position differs from the Hibernate-loaded one).

saveOrUpdate() yields similar results.

Does an intelligent (one or as few as possible lines-of-code) solution exist? Or does one have to work around that behaviour, e.g. by recursing over the object tree and saving (as in associate with the session) the transient objects first?

(P.S.: I get that exception now because I threw an old, custom made subclass named AuftragEntityPersister away - which purged the whole object tree from the database and then inserted the stuff again, probably to work around that very problem.)

Cf. the exception stacktrace:

13:54:16,052 ERROR [de.redacted.services.persistence.auftrag.AuftragPersistenceSessionBean] Rolling back due to Hibernate-Exception: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [de.redacted.domain.auftrag.Auftragsposition#de.redacted.domain.angebot.AngebotsPositionPK@b4000000]
  at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:190) [:3.6.6.Final]
  at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:415) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:341) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:258) [:3.6.6.Final]
  at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:877) [:3.6.6.Final]
  at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:859) [:3.6.6.Final]
  at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:279) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204) [:3.6.6.Final]
  at org.hibernate.engine.Cascade.cascade(Cascade.java:161) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:630) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:490) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:255) [:3.6.6.Final]
  at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84) [:3.6.6.Final]
  at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867) [:3.6.6.Final]
  at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851) [:3.6.6.Final]
  at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855) [:3.6.6.Final]
  at de.redacted.services.persistence.auftrag.AuftragPersistenceSessionBean.saveAuftrag(AuftragPersistenceSessionBean.java:1145) [:]
  at de.redacted.services.persistence.auftrag.AuftragPersistenceSessionBean.saveAuftrag(AuftragPersistenceSessionBean.java:873) [:]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_21]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_21]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_21]
  at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_21]
  at org.jboss.invocation.Invocation.performCall(Invocation.java:386) [:6.1.0.Final]
  at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:233) [:6.1.0.Final]
  at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:156) [:6.1.0.Final]
  at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:173) [:6.1.0.Final]
  at org.jboss.ejb.plugins.CallValidationInterceptor.invoke(CallValidationInterceptor.java:63) [:6.1.0.Final]
  at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:121) [:6.1.0.Final]
  at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:350) [:6.1.0.Final]
  at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:181) [:6.1.0.Final]
  at org.jboss.ejb.plugins.SecurityInterceptor.process(SecurityInterceptor.java:228) [:6.1.0.Final]
  at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:211) [:6.1.0.Final]
  at org.jboss.ejb.plugins.security.PreSecurityInterceptor.process(PreSecurityInterceptor.java:100) [:6.1.0.Final]
  at org.jboss.ejb.plugins.security.PreSecurityInterceptor.invoke(PreSecurityInterceptor.java:84) [:6.1.0.Final]
  at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:205) [:6.1.0.Final]
  at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:138) [:6.1.0.Final]
  at org.jboss.ejb.SessionContainer.internalInvoke(SessionContainer.java:650) [:6.1.0.Final]
  at org.jboss.ejb.Container.invoke(Container.java:1072) [:6.1.0.Final]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_21]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_21]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_21]
  at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_21]
  at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157) [:6.0.0.GA]
  at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96) [:6.0.0.GA]
  at org.jboss.mx.server.Invocation.invoke(Invocation.java:88) [:6.0.0.GA]
  at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:271) [:6.0.0.GA]
  at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:670) [:6.0.0.GA]
  at org.jboss.invocation.unified.server.UnifiedInvoker.invoke(UnifiedInvoker.java:232) [:6.1.0.Final]
  at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:967) [:6.1.0.Final]
  at org.jboss.remoting.transport.socket.ServerThread.completeInvocation(ServerThread.java:791) [:6.1.0.Final]
  at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:744) [:6.1.0.Final]
  at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:586) [:6.1.0.Final]
  at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:234) [:6.1.0.Final]
1

There are 1 best solutions below

0
On

Status update:

If this had been the whole problem, I would have solved it by running by recursing over the object tree (at least to a certain depth). Not nice but at least rare. ;o)

Having some other ugly requirements (this is a legacy data model), I finally left the custom Persister subclass in place.