2
votes

I have two entities defined in JPA: Employee and Skill.

Between this entities is defined relationship @ManyToMany.

public class Employee { 

     @ManyToMany(fetch = FetchType.LAZY)
     @JoinTable(name = "employee_skill",
        joinColumns = @JoinColumn(name = "employee_id"),
        inverseJoinColumns = @JoinColumn(name = "skill_id")
     )
     private Set<Skill> skills = new HashSet<>();
}

public class Skill { 

     @ManyToMany(mappedBy = "skills", fetch = FetchType.LAZY)
     private Set<Employee> skilledEmployees = new HashSet<>(); 
}

Now I have such problem: If I remove Skill entity using entity manager. It removes ok. But in @JoinTable in database employee_skill there remains associations with this removed entity (its id).

I do not want to remove Employee when I am removing Skill so all CASCADE REMOVING or orphanRemoval are not useful here.

I consider why this relationship isn't automagically removed from database. When this association in join table remains it gives me javax.persistence.EntityNotFoundException: Unable to find...

So I could remove this associations manually, before removing Skill entity. But is it really the best practice?

What will be the best practice to remove entities in @ManyToMany bidirectional relationships? When removing one entity like Employee or Skill shouldn't effect the other entity?

1
setting both sides of a relation is the only real way ... since you chose to have a BIdirectional relation - Neil Stockton
you mean unsetting? like for employee : skill.getEmployees() { employee.remove(skill); } when removing skill entity from db - Michał Ziobro
indeed. "setting" means making both Collections consistent, BEFORE passing to the persistence mechanism (i.e before flush, commit). What you should do with all BIdirectional relations - Neil Stockton
Yeah I know, but cause I'm not native English I would like to ensure that in this case I need to remove on both sides association on this entities to make this relationship "setting" correctly :) - Michał Ziobro

1 Answers

0
votes

Since Employee is the owning side (based on your mappedBy value) of the relationship, any update on its relationship with Skill objects would update the database associations. That's the responsibility of the owning side and it would fulfill that. But the other way around is not gonna happen. One of your possible solutions is to define database cascade rules manually, something like following in the join table:

FOREIGN KEY (skill_id) REFERENCES skills (id)
  MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE

This way, any update to Skills would update the associations in database.

The other approach is to change the owning side to Skill by defining a mappedBy in Employee, which does not feel that natural based on Employee/Skill stereotypical relationships.