5 Replies Latest reply on Dec 2, 2008 3:23 PM by valatharv

    Cannot remove entites used in relationships

    andydale

      Hi,

      I have set up a very simple entity model to test relationships in EJB3. I have no problems in adding to them, and removing an entity so long as it is not used in a relationship (not refered to as a foriegn key value).

      The problem occurs when trying to remove the entity when it is used in a relationship be it many to many or many to one/one to many. Another thing to note about the relationships between the entites is that on the owning side a java.util.Set is used and on the non-owning side a java.util.Collection is used. To give an example of a this in a many to many context.

      I have 3 Entities Student, Course, and Institution and all of these relationships are many to many (please see below).
      In Student.java the student-course many to many and collection declaration

      private Collection<Course> mCourses = new ArrayList<Course>();
      
      @ManyToMany(mappedBy = "students", fetch = FetchType.EAGER, cascade ={CascadeType.PERSIST, CascadeType.MERGE})
       public Collection<Course> getCourses() {
       return mCourses;
       }
      


      in Course.java student-course many to many and collection declarations/b]
      private Set<Student> mEnrolledStudents = new HashSet<Student>();
      
       @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
       @JoinTable(name = "course_student",
       joinColumns = @JoinColumn(name = "course_id", referencedColumnName = "course_id"),
       inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "student_id"))
       public Set<Student> getStudents() {
       return mEnrolledStudents;
       }



      in Course.java course-institution many to many and collection declaration
      private Collection<Institution> mInstitutionsRunningCourse = new ArrayList<Institution>();
      
      @ManyToMany(mappedBy = "courses", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
       public Collection<Institution> getInstitutions() {
       return mInstitutionsRunningCourse;
       }



      in Institution.java course-institution many to many
      private Set<Course> mCoursesOffered = new HashSet<Course>();
      
      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
       @JoinTable(name = "institution_course",
       joinColumns = @JoinColumn(name = "institution", referencedColumnName = "institution_id") ,
       inverseJoinColumns = @JoinColumn(name = "course", referencedColumnName = "course_id") )
       public Set<Course> getCourses() {
       return mCoursesOffered;
       }



      I create a course with 3 students on it (3 entries in the association table) and also link this course to 2 institutions (2 entries in the association table). Then i try to call the EntityManager.remove() method from within the same SLSB. The error i get is this

      Caused by: java.lang.RuntimeException: org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dale.comsoft.de/50, BranchQual=, localId=50] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.persistence.EntityNotFoundException: org.hibernate.ObjectDeletedException: deleted entity passed to persist: [test.Course#<null>])
      at org.jboss.aspects.tx.TxPolicy.handleEndTransactionException(TxPolicy.java:198)
      at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:180)
      at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
      at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:197)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:78)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
      at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
      at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:181)
      at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:79)
      at $Proxy347.tryDelete(Unknown Source)
      at test.TestRelationships.storeData(TestRelationships.java:63)
      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.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
      ... 29 more
      Caused by: org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=dale.comsoft.de/50, BranchQual=, localId=50] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.persistence.EntityNotFoundException: org.hibernate.ObjectDeletedException: deleted entity passed to persist: [test.Course#<null>])
      at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:372)
      at org.jboss.tm.TxManager.commit(TxManager.java:240)
      at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:175)
      ... 51 more
      Caused by: javax.persistence.EntityNotFoundException: org.hibernate.ObjectDeletedException: deleted entity passed to persist: [test.Course#<null>]
      at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:564)
      at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:484)
      at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1491)
      at org.jboss.tm.TransactionImpl.beforePrepare(TransactionImpl.java:1110)
      at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:324)
      ... 53 more
      Caused by: org.hibernate.ObjectDeletedException: deleted entity passed to persist: [test.Course#<null>]
      at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:90)
      at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:646)
      at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:638)
      at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:225)
      at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:213)
      at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:157)
      at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
      at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:290)
      at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:185)
      at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:160)
      at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:108)
      at org.hibernate.engine.Cascade.cascade(Cascade.java:248)
      at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:130)
      at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:121)
      at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65)
      at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
      at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:993)
      at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:340)
      at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:475)
      ... 56 more



      I cannot figure out what is wrong, I even tried to clear the set and collection first thus leaving the database in the correct state (tested it by just calling persist and not remove) then removing the entity and i still get the same error.

      I have also tried annotating with this :
      @org.hibernate.annotations.Cascade( {
       org.hibernate.annotations.CascadeType.ALL,
       org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
      


      but that does not work.

      Can anyone shed any light on where i have gone wrong ?

      Thanks in advance,

      Andy

        • 1. Re: Cannot remove entites used in relationships
          andydale

          Hi,

          I managed to fix my problem. It was down to the fact the on deleting a Course you need to remove it from the list/collections of the non-owning side of the relationship.

          Thanks,

          Andy

          • 2. Re: Cannot remove entites used in relationships
            bathulap

            Problem :
            Relation between ManualCheck & ManualCheckDistribution is one to many, ManualCheckDistribution to ManualCheckDistributionDetail is one to many.

            When I tried to invoke delete Child), hibernate is throwing below exception. Though we are trying to delete entity, error message talks about persisting an entity.

            javax.persistence.EntityNotFoundException: deleted entity passed to persist: [com.adp.payroll.model.payroll.manualcheck.ManualCheckDistribution#]

            Guess hibernate will invoke persist of Parent entity after removing child entity to synchronize its state with database.

            Parent entity Set/Collection of child entities has still a reference to Child entity which was deleted, because we have not refreshed Set/Collection of child entities in Parent entity.

            When Hibernate calls persist on Parent to synchronize we get the above exception.

            Soution : Before you invoke delete(Child), remove the child entity refernce from the Set/Collection of child entities in Parent entity
            Code snippet:
            public void deleteManualCheckDistribution(PayrollAgreementId payrollAgreementId, String payNumber, int distNumber )throws PayrollServiceException {
            ManualCheckDistribution checkDist = getManualCheckDistribution(payrollAgreementId, payNumber, distNumber);
            ManualCheck mc = checkDist.getManualCheck();
            Set distList = mc.getManualCheckDistributions();
            distList.remove(checkDist);
            getEm().remove(checkDist);
            }

            Thanks,
            Bathula.

            • 3. Re: Cannot remove entites used in relationships
              waynebaylor

              did you remove all references other entities may have to the Child entity?

              • 4. Re: Cannot remove entites used in relationships
                bathulap

                Yes,

                you need to remove the references.

                The cardinal rule for this is: before removing, adding an object, or assiging an object to differentowner, always wire the relationship in your java code.

                Thanks,
                Bathula

                • 5. Re: Cannot remove entites used in relationships
                  valatharv

                  I need help while deleting child entity, please suggest how can I handle it. I tried posting in seam forum but that is not the right place..

                  I am stuck and need help... :( new to this...

                  Entity Overview :
                  -Project entity can have multiple QuantExperiments.
                  -QuantExperiment entity can have multiple Reagents and
                  -Reagent entity can have multiple Treatments.

                  As per functionalities user can CREATE, UPDATE or DELETE any entity from UI.

                  I created few Treatments for Reagents and few reagents for experiments, etc.

                  Now, when I try to delete only ONE treatment from Treatment home it gives exception as :
                  ----------------------
                  Caused by: javax.persistence.EntityNotFoundException: deleted entity passed to persist: [com.entity.Treatment#]
                  at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:613)
                  at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:299)
                  at org.jboss.seam.persistence.EntityManagerProxy.flush(EntityManagerProxy.java:90)
                  at org.jboss.seam.framework.EntityHome.remove(EntityHome.java:108)
                  at com.TreatmentHome.remove(TreatmentHome.java:86)
                  ----------------------

                  I think it is issue with CascadeType but not able to figure out. "TreatmentHome.remove()" is called while (deleting)

                  I tried using various combinations for CascadeType like using but no success.
                  "CascadeType.MERGE,CascadeType.REFRESH,CascadeType.REMOVE" on Reagent.getTreatment() and Treatment.getReagent()

                  Project entity :
                  ----------------
                  public class Project
                   implements Equals, HashCode, ToString{
                  ......
                  
                  protected List<QuantExperiment> quantExperiment;
                  
                  @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy="project")
                  public List<QuantExperiment> getQuantExperiment() {
                   if (quantExperiment == null) {
                   quantExperiment = new ArrayList<QuantExperiment>();
                   }
                   return this.quantExperiment;
                  }
                  
                   public void setQuantExperiment(List<QuantExperiment> quantExperiment) {
                   for(QuantExperiment q : quantExperiment){
                   q.setProject(this);
                   }
                   this.quantExperiment = quantExperiment;
                  }

                  QuantExperiment entity :
                  ------------------------
                  public class QuantExperiment
                   implements Equals, HashCode, ToString {
                  ......
                  protected List<Reagent> reagent;
                  protected Project project;
                  
                  @OneToMany(cascade = {CascadeType.ALL}, , fetch = FetchType.LAZY, mappedBy="quantExperiment")
                  public List<Reagent> getReagent() {
                   if (reagent == null) {
                   reagent = new ArrayList<Reagent>();
                   }
                   return this.reagent;
                  }
                  
                  public void setReagent(List<Reagent> reagent) {
                   for(Reagent r : reagent){
                   r.setQuantExperiment(this);
                   }
                   this.reagent = reagent;
                  }
                  
                  @ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, optional=false)
                  public Project getProject() {
                   return project;
                  }
                  public void setProject(Project project) {
                   this.project = project;
                  }


                  Reagent entity :
                  ----------------
                  public class Reagent
                   implements Equals, HashCode, ToString {
                  ....
                  protected List<Treatment> treatment;
                  protected QuantExperiment quantExperiment;
                  
                  @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy="reagent")
                  public List<Treatment> getTreatment() {
                   if (treatment == null) {
                   treatment = new ArrayList<Treatment>();
                   }
                   return this.treatment;
                  }
                  public void setTreatment(List<Treatment> treatment) {
                   for(Treatment t : treatment){
                   t.setReagent(this);
                   }
                   this.treatment = treatment;
                  }
                  
                  @ManyToOne(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, optional=false)
                  public QuantExperiment getQuantExperiment() {
                   return quantExperiment;
                  }
                  public void setQuantExperiment(QuantExperiment quantExperiment) {
                   this.quantExperiment = quantExperiment;
                  }


                  Treatment entity :
                  ------------------
                  public class Treatment
                   implements Equals, HashCode, ToString {
                  ......
                  protected Reagent reagent;
                  @ManyToOne(cascade = {CascadeType.ALL},optional=false)
                  public Reagent getReagent() {
                   return reagent;
                  }
                  public void setReagent(Reagent reagent) {
                   this.reagent = reagent;
                  }

                  TreatmentHome.java
                  ------------------
                  @Name("treatmentHome")
                  public class TreatmentHome extends EntityHome<Treatment> {
                  
                  @In(create = true)
                  ReagentHome reagentHome;
                  .....
                  
                  @Override
                  public String remove(){
                   return super.remove();
                  }
                  ....