Relationship N:M - Different object with the same identifier
fabboco Sep 21, 2005 4:05 AMHi,
I have two entity bean G and H related by n:m relationship running on
- Jboss-4.0.3RC2
- EJB_3.0_RC1
@Entity(name = "G") public class G implements Serializable { private Long id; private String property; private Collection<H> hs; @Id(generate = GeneratorType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getProperty() { return property; } public void setProperty(String property) { this.property = property; } @ManyToMany ( targetEntity = H.class, cascade = { CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.EAGER ) public Collection<H> getHs() { return hs; } public void setHs(Collection<H> h) { this.hs = h; } public boolean equals(Object obj) { G tmp = (G) obj; if (id.longValue() == tmp.getId().longValue()) return true; else return false; } }
@Entity(name = "H") public class H implements Serializable { private Long id; private String property; private Collection<G> gs; @Id(generate = GeneratorType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getProperty() { return property; } public void setProperty(String property) { this.property = property; } @ManyToMany ( targetEntity = G.class, cascade = { CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.EAGER, mappedBy = "hs" ) public Collection<G> getGs() { return gs; } public void setGs(Collection<G> gs) { this.gs = gs; } public boolean equals(Object obj) { H tmp = (H) obj; if (id.longValue() == tmp.getId().longValue()) return true; else return false; } }
I presume that the relationship owner is G, so that to delete a related H item I have to unlink it from one or more G items.
I delete h items through a session bean.
@Stateless @Remote(HManager.class) public class HManagerBean implements HManager { @PersistenceContext private EntityManager manager; public void persist(H arg) { manager.persist(arg); } public List findAll() { return manager.createQuery("from H o order by o.id desc").getResultList(); } public H find(java.lang.Long id) { return manager.find(H.class,id); } public H merge(H arg) { return manager.merge(arg); } @TransactionAttribute(TransactionAttributeType.REQUIRED) public void remove(H arg) { Collection<G> gs = arg.getGs(); System.out.print(gs); if(gs == null) { return; } for(G g:gs) { Collection<H> hs = g.getHs(); hs.remove(arg); g.setHs(hs); manager.merge(g); } manager.remove(arg); } }
Now the problem, if call the remove method I get the following error:
Exception in thread "main" javax.ejb.EJBException: null; CausedByException is: a different object with the same identifier value was already associated with the session: [reltest .entity.H#142] at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:46) at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:70) at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:134) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:61) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:3 9) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:63) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:91) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:195) at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:107) at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java :69) at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:566) at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:436) at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:239) at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:291) at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:168) org.hibernate.NonUniqueObjectException: a different object with the same identifier value was alread y associated with the session: [reltest.entity.H#142] at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java: 587) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:70) at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:586) at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:150) at org.jboss.ejb3.entity.InjectedEntityManager.remove(InjectedEntityManager.java:107) at reltest.manager.bean.HManagerBean.remove(HManagerBean.java:65) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:99) at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:32) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:66) at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:134) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:61) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:3 9) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:63) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:91) at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:88) at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:195) at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:107) at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java :69) at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:566) at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:436) at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:239) at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:291) at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:168)
To avoid the error message I have to change the last line:
manager.remove(arg);
into:
manager.remove(manager.find(H.class, arg.getId()));
Where I am wrong ?
Why I have to find the h item again, this costs a new query to the database ?
Why the object I get with the find is different from which I have in the arg parameter ?
Which are the two (or more) objects that I have associated with the session ?
Why can't I do that ?
Any reference to the documentation would be very usefull.
Thank you in advance.
Fabrizio