之间有什么区别
@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教程,但我仍然不了解详细信息。
Answers:
从这里:
级联删除
用CascadeType.REMOVE(或CascadeType.ALL,包括REMOVE)标记引用字段,指示删除操作应自动级联到该字段引用的实体对象(多个实体对象可以被collection字段引用):
@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或另一个地址对象时。
- 如果指定了orphanRemoval = true,则会自动删除断开连接的Address实例。这对于清理没有所有者对象(例如Employee)的引用不应该存在的依赖对象(例如地址)很有用。
- 如果仅指定了cascade = CascadeType.REMOVE,则不会执行自动操作,因为断开关系不是删除
操作。
假设我们有一个子实体和一个父实体。父母可以有几个孩子。
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
Set<Person> myChildern;
}
orphanRemoval是一个ORM概念,它告诉孩子是否为孤儿。它也应该从数据库中删除。
如果无法从其父母访问孩子,则该孩子成为孤儿。例如,如果我们删除“人”对象集(将其设置为空集)或将其替换为新集,那么父级将无法再访问旧集中的子级,并且子级将变为孤儿,因此子级注定是也从数据库中删除。
CascadeType.REMOVE是数据库级别的概念,它指示是否删除了父级,则应该删除其在子表中的所有相关记录。
实际上,区别在于您是要尝试更新数据(PATCH)还是要完全替换数据(PUT)
假设您删除而customer
不是使用cascade=REMOVE
还将删除那些看起来既有用又有用的客户订单。
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
现在,假设您使用进行更新customer
,orphanRemoval="true"
它将删除所有先前的订单,并用提供的订单替换它们。(PUT
就而言REST API
)
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
没有orphanRemoval
旧的命令将被保留。(PATCH
就而言REST API
)
由于这个问题非常普遍,因此此答案基于我在博客上写的这篇文章。
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语句:
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
集合一起加载,然后PostComment
从comments
集合中删除第一个实体:
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
有关此主题的更多详细信息,请同时阅读本文。