重要提示:如果您正在阅读此信息,请考虑查看this post以进行深入讨论。
这是一种非常惯常的做法/情况/要求,父母的子女可能会迁移到另一方父母。如果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;
合并类似以下的操作/操作(其中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);
当然,在相关实体中使用防御性链接(关系)管理方法可以更好地完成/处理添加和删除员工。
部门实例由客户提供。它是一个独立的实体。它可以是相同或不同的部门,具体取决于相关客户执行的管理操作。因此,如果客户提供的部门实例与当前Employee
持有的部门实例不同,则应首先从当前持有的员工列表(employeeList
)中删除该部门实例。与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规范中找不到任何关于此行为的内容。
答案 0 :(得分:3)
JPA specification中记录了这一点。
部分 3.2.4 (摘录):
应用于实体X的刷新操作的语义如下 如下:
- 如果X是托管实体,则会将其同步到数据库。
- 对于来自X的关系引用的所有实体Y,如果与Y的关系已使用级联元素值注释 cascade = PERSIST或cascade = ALL,持久化操作应用于Y
部分 3.2.2 (摘录):
应用于实体X的持久化操作的语义如下 如下:
- 如果X是已移除的实体,则会被管理。
(可选)是否将删除操作应用于实体 已从关系中删除并级联删除 对这些实体的操作。
如果某个实体已从
@OneToMany
集合中移除或已删除 关联实体从@OneToOne
关联中解除引用 如果orphanRemoval
,关联实体可以标记为删除 设为true
。
因此,您从部门E
中删除了该员工D1
,并将她添加到部门D2
。
Hibernate然后将部门D1
与数据库同步,发现E
不在员工列表中,并标记E
以进行删除。然后,它将D2
与数据库同步,并将PERSIST
级联操作到员工列表(第3.2.4节)。由于E
现在在此列表中,因此级联适用于它并且Hibernate取消调度删除操作(第3.2.2节)。
您可能也希望查看此question。
&#34;如果orphanRemoval
在此类关系的反面设置为true
,会发生什么?&#34;
您已将其设置在反面(反面是声明mappedBy
的那面)。如果你的意思是在其他方面(在这种情况下为@ManyToOne
)设置了什么,那么它就没有意义了,这就是为什么没有这样的属性@ManyToOne
和@ManyToMany
。