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