重要通知:如果您正在阅读这篇文章,请考虑查看 this post也可以进行深入讨论。
<小时/> parent 的 child 可能会迁移到另一位 parent 身边,这是一种很常见的做法/情况/要求。如果在此类关系的反面将 orphanRemoval
设置为 true
会发生什么?
以任何简单的一对多关系为例,如下所示。
反面(部门):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employeeList = new ArrayList<Employee>(0);
所有者方(员工):
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private Department department;
在合并如下所示的操作/ Action 时(其中部门
是客户端提供的独立实体),
Employee employee = entityManager.find(Employee.class, 1L);
Department newDepartment = entityManager.contains(department) ? department : entityManager.merge(department);
if (!newDepartment.equals(employee.getDepartment())) {
employee.getDepartment().getEmployeeList().remove(employee);
// Since orphanRemoval is set to true,
// this should cause a row from the database table to be removed inadvertently
// by issuing an addition DELETE DML statement.
}
employee.setDepartment(newDepartment);
employee.setEmployeeName("xyz");
List<Employee> employeeList = newDepartment.getEmployeeList();
if (!employeeList.contains(employee)) {
employeeList.add(employee);
}
entityManager.merge(employee);
当然,添加和删除员工最好使用关联实体中的防御性链接(关系)管理方法来完成/处理。
部门实例由客户提供。它是一个独立的实体。它可以是相同或不同的部门,具体取决于相关客户执行的管理操作。因此,如果客户端提供的部门实例与当前Employee
持有的部门实例不同,则应首先将其从员工列表(employeeList
)中删除。 )由与该员工
相关联的当前旧部门持有,然后将其添加到由提供的新部门
持有的员工列表中.
据猜测,在从员工所在部门当前引用的员工列表中删除 Employee
实例时,应该会无意中从数据库中删除 Employee
行 -旧部门(在触发此操作之前),即在将子项从其父项迁移到另一个父项时,需要先将子项从其 native 父项中删除,然后再由另一个父项收养,并且该子行应该会无意中从其父项中删除数据库(orphanRemoval = true
)。
但是,数据库表中的员工行与更新后的列值保持不变。除了 UPDATE
语句之外,不会生成任何 DML 语句。
我可以考虑一下,以这种方式将子级从其父级迁移到另一个父级,不会无意中从数据库表中删除这些子级,因为它们不应该这样?
当前使用具有 JPA 2.1 的 EclipseLink 2.6.0。
<小时/>编辑:
如果一个Employee
实体只是从反面的列表中删除(因此,在删除后没有添加到列表中 - 没有迁移到另一个父级,而是只是删除),那么它对应的实体行也会照常从数据库中删除 (orphanRemoval = true
),但当 Employee
实体(子级)添加到另一个父级的列表时,该行会被简单更新从其 native 父级列表中删除它之后(实体的迁移)。
提供商似乎足够聪明,能够检测到子级从其父级迁移到另一个父级的情况,作为更新。
在 Hibernate(4.3.6 Final)和 EclipseLink(2.6.0)上可以看到该行为是相同的,但如果它是提供者特定的行为(不可移植),则不能依赖它。我在 JPA 规范中找不到任何有关此行为的信息。
最佳答案
这记录在 JPA specification 中.
第 3.2.4 节(摘录):
The semantics of the flush operation, applied to an entity X are as follows:
- If X is a managed entity, it is synchronized to the database.
- For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y
第 3.2.2 节(摘录):
The semantics of the persist operation, applied to an entity X are as follows:
- If X is a removed entity, it becomes managed.
(Optional) Whether to apply the remove operation to entities that have been removed from the relationship and to cascade the remove operation to those entities.
orphanRemoval
Hibernate docs :
If an entity is removed from a
@OneToMany
collection or an associated entity is dereferenced from a@OneToOne
association, this associated entity can be marked for deletion iforphanRemoval
is set totrue
.
因此,您从部门 D1
中删除员工 E
,并将她添加到部门 D2
。
然后,Hibernate 将部门 D1
与数据库同步,发现 E
不在员工列表中,并将 E
标记为删除。然后,它将 D2
与数据库同步,并将 PERSIST
操作级联到员工列表(第 3.2.4 节)。由于 E
现在位于此列表中,因此级联将应用于它,并且 Hibernate 会取消安排删除操作(第 3.2.2 节)。
您可能想看看这个question也是如此。
“如果在此类关系的反面将 orphanRemoval
设置为 true
,会发生什么?”
您已经将其设置在反面(反面是声明mappedBy
的一面)。如果您的意思是如果它设置在另一侧(在本例中是@ManyToOne
),那么它就没有意义,这就是为什么在中没有这样的属性@ManyToOne
和 @ManyToMany
。
关于hibernate - 将 child 从其 parent 迁移到另一个 parent 时将 orphanRemoval 设置为 true,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30996141/