之间有什么区别
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
和
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
此示例来自Java EE Tutorial,但我仍然不了解详细信息。
答案 0 :(得分:126)
来自here: -
级联删除
使用CascadeType.REMOVE(或CascadeType.ALL)标记引用字段, 其中包括REMOVE)表示删除操作应该是 自动级联到由其引用的实体对象 字段(集合可以引用多个实体对象) 场):
@Entity class Employee { : @OneToOne(cascade=CascadeType.REMOVE) private Address address; : }
孤儿删除
JPA 2支持额外且更积极的删除级联模式 可以使用的orphanRemoval元素指定 @OneToOne和@OneToMany注释:
@Entity class Employee { : @OneToOne(orphanRemoval=true) private Address address; : }
<强>区别: - 强>
两个设置之间的区别在于响应 断开关系。例如,例如设置时 地址字段为null或另一个Address对象。
- 如果指定 orphanRemoval = true ,则会自动删除已断开连接的地址实例。这对清理很有用 在没有a的情况下不应该存在的依赖对象(例如地址) 来自所有者对象(例如,员工)的引用。
- 如果仅指定 cascade = CascadeType.REMOVE ,则不会执行自动操作,因为断开关系不是删除
操作
答案 1 :(得分:70)
了解CascadeType.REMOVE
和orphanRemoval=true
之间差异的简便方法。
孤儿摘除:
如果您调用setOrders(null)
,则相关的Order
实体将自动在数据库中删除。
删除级联:
如果您调用setOrders(null)
,相关的Order
实体将自动在数据库中删除 NOT 。
答案 2 :(得分:3)
假设我们有一个子实体和一个父实体。父母可以有几个孩子。
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
List<Personnel> myChildernList;
}
orphanRemoval是一个ORM概念,它告诉孩子是否是孤儿。还应将其从数据库中删除。
如果无法从其父级访问该子级,则该子级将成为孤儿。 例如,如果我们删除索引i处的obj(使用myChildernList.remove(i))或将其设置为null或将其替换为新的(personnelList.set(i,newChild)),则父级将无法再访问该子级并且该孩子是孤儿,因此该孩子也注定要从数据库中删除(这是令人心碎的:()
CascadeType.REMOVE是数据库级别的概念,它告知是否删除了父级,应该删除其在子表中的所有相关记录。
答案 3 :(得分:2)
由于这个问题非常普遍,因此此答案基于我在博客上写的this article。
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
有关此主题的更多详细信息,请同时查看this article。
答案 4 :(得分:0)
实际上,区别在于您是要尝试更新数据(PATCH)还是要完全替换数据(PUT)
假设您删除customer
而不是使用cascade=REMOVE
也会删除客户的订单,这些订单似乎是有意的和有用的。
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
现在,假设您将customer
更新为orphanRemoval="true"
,它将删除所有先前的订单,并将其替换为提供的订单。 (按PUT
的{{1}})
REST API
没有@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
的旧订单将被保留。 (按orphanRemoval
的{{1}})