0 Replies Latest reply on Sep 16, 2005 4:46 PM by Fabrizio Boco

    Relationship N:M and Transaction Management

    Fabrizio Boco Newbie

      Hi,

      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:39)
       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 already 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:39)
       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