JPA 2.0 orphanRemoval = true删除Cascade时的VS.

Mar*_*kis 172 hibernate jpa cascade cascading-deletes jpa-2.0

我对JPA 2.0 orphanRemoval属性有点困惑.

当我使用JPA提供程序的数据库生成工具创建底层数据库DDL以获得ON DELETE CASCADE特定关系时,我想我可以看到它是必需的.

但是,如果数据库存在并且它已经存在ON DELETE CASCADE关系,那么这还不足以级联删除吗?什么是orphanRemoval除了做?

干杯

axt*_*avt 260

orphanRemoval与此无关ON DELETE CASCADE.

orphanRemoval是一个完全由ORM特定的东西.它标记"子"实体,当它不再从"父"实体引用时被删除,例如,当您从父实体的相应集合中删除子实体时.

ON DELETE CASCADE是一个特定数据库的东西,它删除"父"行时删除数据库中的"子"行.

  • 不,它没有同样的效果.ON DELETE CASCADE告诉DB删除父项时删除所有子记录.即如果我删除INVOICE,则删除该INVOICE上的所有项目.OrphanRemoval告诉ORM如果我从属于Invoice对象的Items集合中删除Item对象(在内存操作中),然后"保存"Invoice,则应从底层DB中删除已删除的Item. (93认同)
  • 如果你使用单向关系,那么即使你没有设置 orphanRemoval=true 也会自动删除孤儿 (4认同)
  • 这是否意味着它们具有安全效果,但是不同的系统是否有责任实现它? (2认同)

for*_*has 83

这里采用的示例如下:

当一个Employee实体对象被移除,删除操作被级联到引用的Address实体对象.在这方面,orphanRemoval=true并且cascade=CascadeType.REMOVE是相同的,并且如果orphanRemoval=true指定的话,CascadeType.REMOVE则是多余的.

两个设置之间的区别在于断开关系的响应.例如,例如将地址字段设置null为另一个Address对象时.

  • 如果orphanRemoval=true指定,Address则自动删除已断开连接的实例.这对于清除在Address没有所有者对象(例如Employee)的引用时不应存在的依赖对象(例如)是有用的.

  • 如果仅cascade=CascadeType.REMOVE指定,则不会执行自动操作,因为断开关系不是删除操作.

为避免因孤立删除而悬挂引用,仅应为包含私有非共享依赖对象的字段启用此功能.

我希望这更清楚.


Onu*_*nur 45

从集合中删除子实体的那一刻,您也将从数据库中删除该子实体.orphanRemoval也暗示你不能改变父母; 如果有一个拥有员工的部门,一旦你删除该员工将其放入另一个部门,你就会在刷新/提交时无意中从数据库中删除该员工(无论哪个先来).士气是将orphanRemoval设置为true,只要您确定该父级的子女在其存在期间不会迁移到不同的父级.启用orphanRemoval还会自动将REMOVE添加到级联列表中.

  • 完全正确......也称为"私人"父母/子女关系. (3认同)
  • 这意味着只要我调用“department.remove(emp);”,该员工就会从 emp 表中删除,甚至无需调用“commit()” (2认同)

Vla*_*cea 25

实体状态转换

JPA 将实体状态转换转换为 SQL 语句,如 INSERT、UPDATE 或 DELETE。

JPA 实体状态转换

当您persist是实体时,您正在安排 INSERT 语句在EntityManager刷新时执行,无论是自动还是手动。

当您remove是一个实体时,您正在调度 DELETE 语句,该语句将在刷新持久性上下文时执行。

级联实体状态转换

为方便起见,JPA 允许您将实体状态转换从父实体传播到子实体。

所以,如果你有父母Post,有一个实体@OneToMany与关联PostComment子实体:

Post 和 PostComment 实体

实体中的comments集合Post映射如下:

@OneToMany(
    mappedBy = "post", 
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<Comment> comments = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

级联类型.ALL

cascade属性告诉 JPA 提供程序将实体状态转换从父Post实体传递到集合中PostComment包含的所有实体comments

因此,如果您删除Post实体:

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

entityManager.remove(post);
Run Code Online (Sandbox Code Playgroud)

JPA 提供程序将首先删除PostComment实体,当所有子实体都被删除时,它也会删除该Post实体:

DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2

DELETE FROM post WHERE id = 1
Run Code Online (Sandbox Code Playgroud)

孤儿移除

当您将该orphanRemoval属性设置为 时true,JPA 提供程序将在remove从集合中删除子实体时安排操作。

所以,在我们的例子中,

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());

post.getComments().remove(postComment);
Run Code Online (Sandbox Code Playgroud)

JPA 提供程序将删除关联的post_comment记录,因为集合中PostComment不再引用该实体comments

DELETE FROM post_comment WHERE id = 1
Run Code Online (Sandbox Code Playgroud)

删除级联

ON DELETE CASCADE是在FK级别定义:

ALTER TABLE post_comment 
ADD CONSTRAINT fk_post_comment_post_id 
FOREIGN KEY (post_id) REFERENCES post 
ON DELETE CASCADE;
Run Code Online (Sandbox Code Playgroud)

一旦你这样做,如果你删除post一行:

DELETE FROM post WHERE id = 1
Run Code Online (Sandbox Code Playgroud)

post_comment数据库引擎会自动删除所有关联的实体。但是,如果您错误地删除了根实体,这可能是一个非常危险的操作。

结论

JPAcascadeorphanRemoval选项的优点是您还可以从乐观锁定中受益,以防止丢失更新。

如果使用 JPA 级联机制,则不需要使用 DDL-level ON DELETE CASCADE,如果删除在多个级别上具有许多子实体的根实体,这可能是非常危险的操作。

  • 我在我的高性能 Java 持久性 GitHub 存储库中添加了这两个示例](https://github.com/vladmihalcea/high-performance-java-persistence/commit/76136289351fdbcfe68f1cdd25b10450df0412c9),它们演示了这一切是如何工作的。您不需要像通常直接删除实体那样同步子端。然而,孤立删除仅在添加级联时才有效,但这似乎是 Hibernate 的限制,而不是 JPA 规范。 (3认同)
  • 我不明白一件事:如果我们从不删除 M 端的连接,孤儿删除将如何在双向映射中启动?我认为从 Post 列表中删除 PostComment 而不将 PostComment.post 设置为 null 不会导致删除数据库中这两个实体之间的连接。这就是为什么我认为孤儿移除不会启动,在关系世界中 PostComment 不是孤儿。当我有空闲时间时我会测试它。 (2认同)

Her*_*eri 17

DDL的等效JPA映射ON DELETE CASCADEcascade=CascadeType.REMOVE.孤立删除意味着在与其"父"实体的关系被销毁时删除依赖实体.例如,如果从@OneToMany关系中删除子项而未在实体管理器中明确删除它.


小智 7

区别是:
-orphanRemoval = true:当不再引用“子”实体时,“子”实体将被删除(其父对象可能不会被删除)。
-CascadeType.REMOVE:仅在删除其“父项”时,才删除“子级”实体。


pze*_*zko 6

@GaryK答案是绝对伟大,我花了一个小时寻找一个解释orphanRemoval = trueVS CascadeType.REMOVE,它帮助我理解。

总结:仅当我们删除对象 ( ) 并且我们希望子对象也被删除时,它的orphanRemoval = true工作方式相同。CascadeType.REMOVE entityManager.delete(object)

在完全不同的情况下,当我们获取一些数据List<Child> childs = object.getChilds(),然后删除子 ( entityManager.remove(childs.get(0)) 时,orphanRemoval=true会导致对应的实体childs.get(0)从数据库中删除。