如何使用Hibernate和JPA在多对多关系中删除孤儿实体?

28

我想使用Hibernate和JPA删除孤立的实体,但我找到的所有内容都是针对一对多关系的org.hibernate.annotations.CascadeType.DELETE_ORPHAN属性,而不适用于多对多关系。

我想知道是否可以删除我的多对多关系中的孤立实体。

4个回答

15

来自书籍 "Pro JPA 2":

只有源端的单一基数关系才能启用孤儿删除,这就是为什么孤儿删除选项在 @OneToOne 和 @OneToMany 的关系注解上定义,但不在 @ManyToOne 或 @ManyToMany 注解上定义的原因。

很遗憾,对于 ManyToMany 没有 JPA 自动化的孤儿删除功能。


7

实际上,我对以下实体进行了测试:

@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>();

    //...
}

以下是给定的数据集:

<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>

以下是测试方法:
@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();
}

只是通过了。以下是生成的输出:

Hibernate:从Person表中选择id、firstName和lastName,其中id=?
Hibernate:从Person_Role表中选择persons_id和roles_id,左外连接Role表,其中roles_id=Role表的id,且persons_id=?
Hibernate:从Person_Role表中删除persons_id=?
Hibernate:从Role表中删除id=?
Hibernate:从Role表中删除id=?
Hibernate:从Person表中删除id=?
Hibernate:从Person表中选择id、firstName和lastName
Hibernate:从Role表中选择id和name

2
是的!我也测试过了。它确实删除了所有相关联的角色(在这种情况下),但我不能这么做。我只需要删除那些孤立的角色... 感谢您的帮助! - Alucard
@user368453:确实,就像Hibernate级联删除一样(我现在明白这不是你想要的)。我想知道Hibernate能否做得更好。 - Pascal Thivent
是的!我希望它可以……但似乎我必须在数据库上创建一个触发器来实现这个目标 =/ - Alucard
这个解决方案还依赖于Hibernate,并且破坏了JPA的可移植性。 - Dave
5
请不要使用此功能,即使相关实体不是孤立的,它也会删除这些实体。 - ihebiheb

6

到目前为止,ManyToMany注释中没有orphanRemoval属性。我也遇到了同样的问题。而在数据库上实现它的建议并不能解决这个问题。JPA的整个哲学是通过映射而不是在数据库上实现逻辑来处理问题。


-27

试试这个:

@ManyToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY, mappedBy = "yourObject")

1
就像下面的评论所说,ManyToMany注释上没有这样的属性。 - cproinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接