Tin*_*iny 6 hibernate jpa eclipselink orphaned-objects orphan
重要提示:如果您正在阅读本文,请考虑深入讨论这篇文章.
这是一种很常见的做法/情况/要求,父母的子女可能会迁移到另一方父母.如果orphanRemoval设置true在这种关系的反面,会发生什么?
以一个例子为例,任何简单的一对多关系如下.
反面(部门):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employeeList = new ArrayList<Employee>(0);
Run Code Online (Sandbox Code Playgroud)
拥有方(员工):
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private Department department;
Run Code Online (Sandbox Code Playgroud)
合并如下所示的操作/操作(其中department是客户端提供的分离实体),
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);
Run Code Online (Sandbox Code Playgroud)
当然,可以使用关联实体中的防御性链接(关系)管理方法来更好地完成/处理添加和移除员工.
部门实例由客户提供.它是一个独立的实体.它可以是相同或不同的部门,具体取决于相关客户执行的管理操作.因此,如果客户提供的部门实例与当前持有的部门实例不同Employee,则应首先从employeeList当前旧部门持有的employee()列表中删除,该部门与Employee添加之前相关联它到新department提供的员工名单.
作为猜测,Employee应该从数据库中无意中删除该行,同时Employee从员工部门 - 旧部门当前引用的员工列表中删除该实例(在此操作被触发之前),即将子项从其父项迁移到另一个父级,在另一个父级采用子级之前,需要将其从其本机父级中删除,并且该子级别应该无意中从数据库中删除(orphanRemoval = true).
但是,数据库表中的雇员行与更新的列值保持不变.除了语句之外,UPDATE不会生成任何DML语句.
我可以考虑,以这种方式将孩子从父母迁移到另一个父母,不会无意中将这些孩子从数据库表中删除,因为他们不应该这样做吗?
目前使用具有JPA 2.1的EclipseLink 2.6.0.
编辑:
如果Employee实体仅被删除(因此,在删除后未添加到列表中 - 未迁移到另一个父项但刚刚删除)从反面列表中删除,则其对应的行也会像往常一样从数据库中删除(orphanRemoval = true)但是,当Employee实体(子)从其本机父项列表中删除(实体的迁移)后,将该实体(子)添加到另一个父项的列表中时,该行只会更新.
提供者似乎足够聪明,可以检测孩子从父母迁移到另一个父母的过程,作为更新.
在Hibernate(4.3.6 final)和EclipseLink(2.6.0)上可以看到相同的行为,但如果它是特定于提供者的行为(不可移植),则不能依赖它.我在JPA规范中找不到任何关于此行为的信息.
JPA 规范中记录了这一点。
第3.2.4节(摘录):
应用于实体 X 的刷新操作的语义如下:
- 如果 X 是托管实体,则将其同步到数据库。
- 对于由 X 的关系引用的所有实体 Y,如果与 Y 的关系已使用级联元素值cascade=PERSIST 或cascade=ALL 进行注释,则持久操作将应用于 Y
第3.2.2节(摘录):
应用于实体 X 的持久操作的语义如下:
- 如果 X 是已删除的实体,则它将变为托管实体。
(可选)是否将删除操作应用于已从关系中删除的实体,并将删除操作级联到这些实体。
如果从集合中删除实体
@OneToMany或从关联中取消引用关联实体,则如果设置为 ,@OneToOne则可以将该关联实体标记为删除。orphanRemovaltrue
因此,您E从部门中删除该员工D1并将她添加到该部门D2。
然后,Hibernate 将该部门D1与数据库同步,发现该部门E不在员工列表中,并标记E为删除。然后它D2与数据库同步并将PERSIST操作级联到员工列表(第3.2.4节)。由于E现在位于此列表中,因此级联将应用于它,并且 Hibernate 会取消安排删除操作(第 3.2.2 节)。
您可能也想看看这个问题。
orphanRemoval“如果设置为true这种关系的反面,会发生什么?”
您已经将其设置在反面(反面是声明的一面mappedBy)。如果您的意思是如果它设置在另一侧(@ManyToOne在本例中),那么它就没有意义,这就是为什么@ManyToOneand中没有这样的属性@ManyToMany。
| 归档时间: |
|
| 查看次数: |
1481 次 |
| 最近记录: |