什么是区别?
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
和
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
这个例子来源于Java EE教程,但我仍然不明白细节。
什么是区别?
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
和
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
这个例子来源于Java EE教程,但我仍然不明白细节。
来自这里:
级联删除
将一个引用字段标记为CascadeType.REMOVE(或包含REMOVE的CascadeType.ALL),表示删除操作应该自动级联到被该字段引用的实体对象上(多个实体对象可以被一个集合字段引用):
@Entity
class Employee {
:
@OneToOne(cascade=CascadeType.REMOVE)
private Address address;
:
}
孤儿对象的移除
JPA 2支持一种更加积极的级联删除模式,可以使用@OneToOne和@OneToMany注解中的orphanRemoval元素指定:
@Entity
class Employee {
:
@OneToOne(orphanRemoval=true)
private Address address;
:
}
区别:
这两个设置的区别在于对关系断开的响应。例如,当将地址字段设置为null或另一个地址对象时。
假设我们有一个子实体和一个父实体。一个父亲可以有几个孩子。
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
Set<Person> myChildern;
}
< p >orphanRemoval是ORM概念,它表示如果子对象成为孤儿,则应从数据库中删除。当子对象无法从其父对象访问时,将被视为孤儿。例如,如果我们删除Person对象集(将其设置为空集)或用新集替换它,则父对象将无法访问旧集合中的子对象,这些子对象将成为孤儿,因此将从数据库中删除这些孤儿记录。
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 FROM post_comment
WHERE id = 2
实际上,差异在于您是尝试更新数据(PATCH)还是完全替换数据(PUT)。
假设您删除了customer
,那么使用cascade=REMOVE
将同时删除该客户的订单,这似乎是有意和有用的。
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
现在假设您使用orphanRemoval="true"
更新一个customer
,它将删除所有先前的订单并用提供的订单替换它们。(在REST API
方面使用PUT
)
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
orphanRemoval
,旧订单将被保留。(在REST API
的术语中为PATCH
)