JPA 中的 CascadeType.REMOVE 和 orphanRemove 有什么区别?



两者有什么区别

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

这个例子来自Java EE教程,但我仍然不了解细节。

从这里开始:-

级联删除

使用 CascadeType.MOVE

(或 CascadeType.ALL, 包括删除)指示删除操作应 自动级联到由该引用的实体对象 字段(集合可以引用多个实体对象 字段):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}

孤儿移除

JPA 2 支持附加且更激进的删除级联模式 可以使用 @OneToOne和@OneToMany注释:

@Entity
class Employee {
     :
    @OneToOne(orphanRemoval=true)
    private Address address;
     :
}

差异:-

两种设置之间的区别在于对 断开关系。例如,在设置 地址字段为 null 或其他地址对象。

  • 如果指定了orphanRemoval=true,则会自动删除断开连接的地址实例。这对于清理很有用 没有 来自所有者对象(例如员工)的引用。
  • 如果仅指定了 cascade=CascadeType.REMOVE 则不会执行自动操作,因为断开关系不是删除
    操作。

一种理解CascadeType.REMOVEorphanRemoval=true之间区别的简单方法。

对于孤儿移除:如果调用 setOrders(null) ,相关的Order实体将自动在 db 中删除。

对于删除级联:如果调用 setOrders(null) ,则不会在 db 中自动删除相关的Order实体

假设我们有一个子实体和一个父实体。父母可以有多个孩子。

@Entity
class parent {
  //id and other fields
 @OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
   Set<Person> myChildern;
}

orphanRemoval是一个ORM概念,它告诉孩子是否是孤儿。 它还应该从数据库中删除。

当无法从其父级访问子项时,该子项是孤立项。例如,如果我们删除 Person 对象集(将其设置为空集)或将其替换为新集,则父级无法再访问旧集中的子项,并且子项是孤立的,因此子项注定要在数据库中删除。

CascadeType.REMOVE 是一个数据库级别的概念,它告诉如果父表被删除,子表中的所有相关记录都应该被删除。

CascadeType.REMOVE

可以显式配置的CascadeType.REMOVE策略:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();

或者从CascadeType.ALL策略隐式继承它:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();

允许您将remove操作从父实体传播到其子实体。

因此,如果我们获取父实体Post及其comments集合,并删除post实体:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments
    where p.id = :id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();
entityManager.remove(post);

Hibernate将执行三个删除语句:

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

由于CascadeType.REMOVE策略,删除了PostComment子实体,就像我们也删除了子实体一样。

孤儿清除策略

孤立删除策略,需要通过 orphanRemoval 属性设置:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

允许您在从集合中删除子实体时删除子表行。

因此,如果我们加载Post实体及其comments集合并从comments集合中删除第一个PostComment

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments c
    where p.id = :id
    order by p.id, c.id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();
post.remove(post.getComments().get(0));

Hibernate将为关联的post_comment表行执行DELETE语句:

DELETE FROM post_comment 
WHERE id = 2

实际上,区别在于您是尝试更新数据(PATCH)还是完全替换数据(PUT)

假设您删除了customer,那么使用cascade=REMOVE也会删除客户看似有意和有用的订单。

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

现在,假设您使用orphanRemoval="true"更新customer,它将删除所有以前的订单并用提供的订单替换它们。( PUTREST API而言)

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

没有orphanRemoval旧订单将被保留。( PATCHREST API而言)

相关内容

  • 没有找到相关文章

最新更新