125

有什么区别

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

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

这个例子来自Java EE Tutorial,但我仍然不明白细节。

4

5 回答 5

168

这里:-

级联删除

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

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

孤儿移除

JPA 2 支持额外且更激进的删除级联模式,可以使用 @OneToOne 和 @OneToMany 注释的 orphanRemoval 元素指定:

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

区别:-

两种设置之间的区别在于对断开关系的响应。例如,当将地址字段设置为空或另一个地址对象时。

  • 如果指定了orphanRemoval=true,则断开连接的 Address 实例将被自动删除。这对于清理在没有来自所有者对象(例如 Employee)的情况下不应该存在的依赖对象(例如地址)很有用。
  • 如果仅指定了cascade=CascadeType.REMOVE,则不会采取自动操作,因为断开关系不是删除
    操作。
于 2013-09-15T14:18:47.807 回答
102

CascadeType.REMOVE一个简单的方法来理解和之间的区别orphanRemoval=true

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

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

于 2013-09-15T18:33:34.500 回答
25

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

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

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

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

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

于 2018-11-06T11:52:07.943 回答
9

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

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

孤儿移除策略

孤儿移除策略,需要通过orphanRemoval属性设置:

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

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

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

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
于 2020-07-08T11:14:17.013 回答
4

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

假设您删除了customer比使用cascade=REMOVE也将删除似乎有意和有用的客户订单。

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

现在假设您更新 acustomerorphanRemoval="true"删除所有以前的订单并用提供的订单替换它们。(PUT就 而言REST API

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

没有orphanRemoval旧订单将被保留。(PATCH就 而言REST API

于 2019-07-22T15:03:30.790 回答