2 Replies Latest reply: Feb 21, 2012 10:28 AM by Cdelahun-Oracle RSS

    Deleting parent entity of oneToMany does not delete children first,

    266288
      I have two entities related with a bi-rdirectional OneToMany relationship. When I delete the parent, I want eclipseLink to automatically delete the child entities first before deleting the parent entity. I have implemented what I understand all the documents are telling me I should implement, but I can not get it working.

      When I try and delete the parent I get an SQLException as the foreign key constraint has been violated as there are child records for the parent I am trying to delete. It was my understanding, that if you have all the annotations correct on my Entities, then all i have to do is delete the parent and eclipseLink will delete the children first and therefore i should never get the SQL exception.

      Here is some snippets of my code.


      Entities


      @Entity(name = "PARENTS")
      public class ParentEntity {
           
           @Id
           @Column(name = "PARENT_ID", nullable = false)
           private String parentID;

           @Column(name = "DISPLAY_NAME", nullable = false)
           private String displayName;
           
           @OneToMany(mappedBy="parent", orphanRemoval=true, cascade=CascadeType.ALL)
           private Collection<ChildEntity> childEntities;     

      ...
      }



      @Entity(name = "CHILDREN")
      @IdClass(ChildIdentifier.class)
      public class ChildEntity {

           @Id
           @Column(name="ITEM_ID", nullable=false)
           private String itemID;

           @Id
           @ManyToOne()
           @JoinColumn(name="PARENT_ID", nullable=false)
           private ParentEntity parent;
           
      ....
      }



      public class ChildIdentifier implements Serializable {
           private String itemID;
      private String parent;
      ....
      }


      Tables created from these entities

      PARENTS

      Name Null? Type
      ----------------------------------
      PARENT_ID NOT NULL VARCHAR2(36)
      DISPLAY_NAME NOT NULL VARCHAR2(255)

      PrimaryKey = PARENT_ID


      CHILDREN

      Name Null? Type
      -------------------------------
      ITEM_ID NOT NULL VARCHAR2(36)
      PARENT_ID NOT NULL VARCHAR2(255)

      PrimaryKey = ITEM_ID,PARENT_ID
      ForeignKey = PARENTID = PARENTS.PARENT_ID


      Code to delete a parent

           public void deleteParent(String id)
      {
                ParentEntity e= em.find(ParentEntity .class, id);
                if (e!= null)
                     em.remove(e);
           }


      Exception seen

      javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.0.v20120119-r10715): org.eclipse.persistence.exceptions.DatabaseException
      Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-02292: integrity constraint (MYSCHEMA.CHILDREN_FK_P_PARENTS) violated - child record found

      Error Code: 2292
      Call: DELETE FROM PARENTS WHERE (PARENT_ID = ?)




      I have added eclipse logging entries in my persistence.xml to try and see what is going on
      <property name="eclipselink.logging.level" value="FINE"/>
      <property name="eclipselink.logging.parameters" value="true"/>

      And in my jdev console when running my test, i do not see any queries of CHILDREN before it tries to delete from PARENTS.


      Am I missing something really obvious?

      Thanks in advance.

      Edited by: smaslin on Feb 20, 2012 9:20 AM

      Edited by: smaslin on Feb 21, 2012 5:26 AM
        • 1. Re: Deleting parent entity of oneToMany does not delete children first,
          266288
          I have even tried having "optional=false" on the child's relationship annotation and it made no difference

          parent
               @OneToMany(mappedBy="parent", orphanRemoval=true, cascade=CascadeType.ALL)
               private Collection<ChildEntity> childEntities;     

          child
               @Id
               @ManyToOne(optional=false)
               @JoinColumn(name="PARENT_ID", nullable=false)
               private ParentEntity parent;

          as per doced here : http://javablog.co.uk/2009/12/27/onetomany-fixes-in-jpa-2/



          I have also tried PrivateOwned annotation, again, it made no difference

          parent
               @OneToMany(mappedBy="parent", orphanRemoval=true, cascade=CascadeType.ALL)
          @PrivateOwned
               private Collection<ChildEntity> childEntities;     


          child
               @Id
               @ManyToOne()
               @JoinColumn(name="PARENT_ID", nullable=false)
               private ParentEntity parent;
          • 2. Re: Deleting parent entity of oneToMany does not delete children first,
            Cdelahun-Oracle
            "optional=false" only affects DDL generation, not runtime JPA behavior. PrivateOwned is similar to orphanRemoval in that it should cause the removal of child entities when they are dereferenced from the parent (ie remove them from the parent's collection). Cascade remove or cascade all should be all you need, but PrivateOwned+orphanRemoval should still cause the collection to be removed, as long as there are entities within the Parent's list of children to remove.

            The only case where I can see this not occuring is if you have not been maintaining the bidirectional relationship. That is, if you have added Child entities and set a parent, but not updated the Parent's collection of children to reflect that change. A simple test is to refresh the parent before removal - call em.refresh(e); right before the em.remove(e);. If this works, then you will need to change your application so that when you add parents to a child you also add the child to the parent's list of children - JPA does not maintain relationships for you and not doing so will keep the cache inconsistent with what is in the database.

            Best Regards,
            Chris