JPA CascadeType.ALL无法删除孤儿数据。

143

我使用以下映射在JPA中删除孤立节点时遇到了问题

@OneToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "owner")
private List<Bikes> bikes;

我遇到了数据库中存在的孤立角色问题。

我可以使用注解org.hibernate.annotations.Cascade(Hibernate特有标签),但是显然我不想将我的解决方案绑定到Hibernate实现中。

编辑:看起来JPA 2.0将支持此功能。

11个回答

171

如果您正在使用Hibernate,则必须明确定义注释CascadeType.DELETE_ORPHAN,该注释可与JPA CascadeType.ALL一起使用。

如果您不打算使用Hibernate,则必须先明确删除子元素,然后再删除主记录,以避免任何孤立记录。

执行顺序

  1. 提取要删除的主行
  2. 提取子元素
  3. 删除所有子元素
  4. 删除主行
  5. 关闭会话

使用JPA 2.0,现在可以使用选项orphanRemoval = true

@OneToMany(mappedBy="foo", orphanRemoval=true)

3
谢谢,我最终选择了这条路线。我认为这是JPA规范的一个小疏忽。 - Paul Whelan
13
JPA 2.0标准现在已经将deleteOrphan作为@OneToMany的一个属性。如果您使用最新的Hibernate,可以这样写:@OneToMany(..., deleteOrphan=true) - jeremyh
当我只更新子元素时,执行顺序是什么?孤立的记录会被删除吗? - jAckOdE

113

如果您正在使用JPA 2.0,现在可以使用@xxxToMany注释的orphanRemoval=true属性来删除孤立实体。

事实上,在3.5.2-Final版本中已经弃用了CascadeType.DELETE_ORPHAN


6
实际上,我认为orphanRemoval=true的意思是在我从父对象的集合中删除一个对象时将其删除。请参见http://download.oracle.com/javaee/6/tutorial/doc/bnbqa.html#giqxy。 - Archie
请通过 Archie 的链接。 - Jigar Shah
4
"orphanRemoval=true"也不起作用,必须按照旧的方式处理。 - Joe Almore

49
╔═════════════╦═════════════════════╦═════════════════════╗
║   Action    ║  orphanRemoval=true ║   CascadeType.ALL   ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   delete    ║     deletes parent  ║    deletes parent   ║
║   parent    ║     and orphans     ║    and orphans      ║
╠═════════════╬═════════════════════╬═════════════════════╣
║   change    ║                     ║                     ║
║  children   ║   deletes orphans   ║      nothing        ║
║    list     ║                     ║                     ║
╚═════════════╩═════════════════════╩═════════════════════╝

1
如果我有“cascade = CascadeType.ALL,orphanRemoval = false”,并删除父对象会发生什么?它会删除子对象吗,即使我明确地告诉它不要这样做? - izogfif

12

7

您可以使用 @PrivateOwned 注解来删除孤儿实体,例如:

@OneToMany(mappedBy = "masterData", cascade = {
        CascadeType.ALL })
@PrivateOwned
private List<Data> dataList;

5
谢谢 @reshma ,需要注意的是 @PrivateOwned 是一个 EclipseLink JPA 扩展。 - Paul Whelan

6

我刚发现了这个解决方案,但在我的情况下它不起作用:

@OneToMany(cascade = CascadeType.ALL, targetEntity = MyClass.class, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true) 

orphanRemoval = true 没有作用。


1
在更改生效之前,我需要进行清理和构建。 - maralbjo
哇,我已经找了一个小时,想知道为什么在我的ManyToOne上添加CascadeType.ALL没有级联删除。清理并构建后它就可以了。谢谢@maralbjo。 - Andrew Mairose

4

我曾遇到同样的问题,不明白为什么下面这个条件不能删除孤儿数据。当我执行一个命名删除查询时,在Hibernate(5.0.3.Final)中未删除菜品列表:

@OneToMany(mappedBy = "menuPlan", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Dish> dishes = new ArrayList<>();

我想起来不能使用命名删除查询,而是要使用EntityManager。我使用EntityManager.find(...)方法获取实体,然后使用EntityManager.remove(...)删除它,这样餐具也被删除了。


4

2

只需要使用@OneToMany(cascade = CascadeType.ALL, mappedBy = "xxx", fetch = FetchType.LAZY, orphanRemoval = true)即可。

移除targetEntity = MyClass.class,它将会更好地工作。


1

记录一下,在 JPA2 之前的 OpenJPA 中是 @ElementDependant。


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