I want to delete orphan entities using hibernate and JPA on a many-to-many relationship but all that I found was this attribute the attribute. org.hibernate.annotations.Casc
Actually, I did a test with the following entities:
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
@ManyToMany
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Role> roles = new HashSet<Role>();
//...
}
@Entity
public class Role {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "roles")
private Set<Person> persons = new HashSet<Person>();
//...
}
And with the following dataset:
<dataset>
<PERSON id="1" firstname="john" lastname="doe"/>
<PERSON id="2" firstname="clark" lastname="kent"/>
<PERSON id="3" firstname="james" lastname="bond"/>
<ROLE id="1" name="foo"/>
<ROLE id="2" name="bar"/>
<ROLE id="3" name="boo"/>
<ROLE id="4" name="baz"/>
<PERSON_ROLE persons_id="1" roles_id="1"/>
<PERSON_ROLE persons_id="1" roles_id="2"/>
<PERSON_ROLE persons_id="2" roles_id="2"/>
<PERSON_ROLE persons_id="2" roles_id="3"/>
<PERSON_ROLE persons_id="3" roles_id="1"/>
<PERSON_ROLE persons_id="3" roles_id="4"/>
</dataset>
The following test method:
@Test
public void testCascadeDeleteOrphanOnDelete() {
Person person = entityManager.find(Person.class, 1L);
entityManager.remove(person);
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(2, 3), findAllPersons());
ReflectionAssert.assertPropertyLenientEquals("id", Arrays.asList(3, 4), findAllRoles());
}
private List<Person> findAllPersons() {
return entityManager.createQuery("from Person").getResultList();
}
private List<Role> findAllRoles() {
return entityManager.createQuery("from Role").getResultList();
}
Just passes. Below the produced output:
Hibernate: select personx0_.id as id17_0_, personx0_.firstName as firstName17_0_, personx0_.lastName as lastName17_0_ from Person personx0_ where personx0_.id=? Hibernate: select roles0_.persons_id as persons1_1_, roles0_.roles_id as roles2_1_, rolex1_.id as id18_0_, rolex1_.name as name18_0_ from Person_Role roles0_ left outer join Role rolex1_ on roles0_.roles_id=rolex1_.id where roles0_.persons_id=? Hibernate: delete from Person_Role where persons_id=? Hibernate: delete from Role where id=? Hibernate: delete from Role where id=? Hibernate: delete from Person where id=? Hibernate: select personx0_.id as id17_, personx0_.firstName as firstName17_, personx0_.lastName as lastName17_ from Person personx0_ Hibernate: select rolex0_.id as id18_, rolex0_.name as name18_ from Role rolex0_
So far there is no orphanRemoval attribute for the ManyToMany annotation. I have the same problem too. And the suggestion to implement it to on the database is no answer to the problem. The whole philosophy of JPA is against implementing logic on the database, but through the mappings.
try this:
@ManyToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY, mappedBy = "yourObject")
From the book "Pro JPA 2":
Only relationships with single cardinality on the source side can enable orphan removal, which is why the orphanRemoval option is defined on the @OneToOne and @OneToMany relationship annotations, but on neither of the @ManyToOne or @ManyToMany annotations.
It's a bummer, but there is no JPA automated orphan removal for ManyToMany.