2

I have two entities Business which is composed of a list of Departments

@Entity
@Table(name = "Business")
public class Business implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "Id")
  private Long id;

  @OneToMany(mappedBy = "business", 
       cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
   private List<Department> departments;

   @OneToMany(mappedBy = "business", orphanRemoval = true, 
     cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
   private List<Process> processs;

   @ManyToMany
   private List<Competence> competences;
}


@Entity
@Table(name = "Department")
public class Department implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   @OneToMany(mappedBy = "father", 
        cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
   private List<Department> departments;
}

When I try to remove a business instance I get a Mysql Exception

Cannot delete or update a parent row: a foreign key constraint fails (evac_java.Department, CONSTRAINT FK_Department_Business FOREIGN KEY (Business) REFERENCES Business (Id)):HY000 - null

Which means I can't delete the business instance because it has departments associated with it, but a department cannot exists by itself so I want to delete all business's departments when it gets removed. I thought I would achieve this by adding cascade = CascadeType.REMOVE to the @OneToMany annotation in the business entity, but it does not work.

I did a search on the net and I found a lot of questions similar to this one on stackoverflow but they all suggest the same: add cascade = CascadeType.REMOVE or CascadeType.ALL

So I'm wondering if I'm missing somethig.

I'm using Glassfish 4.1 and EclipseLink

I tried with

@OneToMany(mappedBy = "business", orphanRemoval = true)
private List<Department> departments;

on the business entity but it does not work either

Here's the method I'm using to remove entities which is declared in an abstract class

public void remove(T entity) {
    getEntityManager().remove(getEntityManager().merge(entity));
}
Armando
  • 459
  • 1
  • 8
  • 22
  • i think you should add orphanremoval =true head of your list which you want remove item – Sarkhan Apr 19 '15 at 18:22
  • I did consider this option but is that not redundant with CascadeType.REMOVE and also more aggressive? and in this case it should do but what if I don't need to remove the children? – Armando Apr 19 '15 at 18:26
  • if it is onetomany relation it means that children can not be exist without fatherclass.so if you remove father class it means you must remove related items or update related column null – Sarkhan Apr 19 '15 at 18:39
  • http://stackoverflow.com/questions/18813341/what-is-the-difference-between-cascade-and-orphan-removal-from-db – Sarkhan Apr 19 '15 at 18:44
  • Did you try with both `orphanRemoval` and `cascade` options? Orphan removal simply says to delete orphaned rows (which is the behavior you want) and the cascade option simply says to trigger the delete when the owning side is deleted. Do you have any extra FKs defined besides what you have here? What does the DDL generated look like and what JPA implementation? – John Ament Apr 19 '15 at 22:15
  • I've tried both ´orphanRemoval´ and ´cascade´ options. I'm using JPA 2.0 with EclipseLink on Glassfish 4.1. I edited my question to show the other relationships. – Armando Apr 20 '15 at 00:22
  • On the database the FK ´FK_Department_Business´ in the Department table which references ´Business´.´Id´ it says ON DELETE -> RESTRICTED and ON UPDATE -> RESTRICTED. Obviously it is not generationg properly – Armando Apr 20 '15 at 00:28
  • Have you checked that your collection of departments within your business instance has departments when your call remove on the business entity? JPA can only remove and cascade the remove over entities it knows about, and if you have not been maintaining both sides of this bidirectional relationship, issues like this will arise. If it is empty, try an em.refresh() before the remove, forcing JPA to populate all relationships so that they can be correctly removed, though if it works, you would be better off maintaining the relationship. – Chris Apr 22 '15 at 18:52
  • That was it @Chris, when a persisted the department I set its business but I did not add the new department to the business's department list. If you post your comment as an answer I will accept it. – Armando Apr 24 '15 at 15:40

1 Answers1

2

JPA can only remove and cascade the remove over entities it knows about, and if you have not been maintaining both sides of this bidirectional relationship, issues like this will arise. If the collection of departments is empty, try an em.refresh() before the remove, forcing JPA to populate all relationships so that they can be correctly removed, though it is better to maintain both sides of the relationship as changes are made to avoid the database hit.

Chris
  • 20,138
  • 2
  • 29
  • 43