这是一种很常见的做法/情况/要求,其中父母的子女可以迁移到另一父母。如果orphanRemoval设置为true这种关系的反面会发生什么?
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客户端提供的分离实体)时,
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
employeeList
可以猜测,在Employee从Employee雇员部门- 旧部门当前所引用的雇员列表中删除实例时(在触发此操作之前),即在将孩子从其父项迁移到父项时,应无意中从数据库中删除该行。另一个父级,则需要先从其父级父级中删除该子级,然后再不经意地从数据库(orphanRemoval= true)中删除该子行。
orphanRemoval= true
但是,数据库表中的雇员行与更新的列值保持不变。除一条语句外,UPDATE不生成任何DML语句。
UPDATE
我是否可以考虑以这种方式将子代从其父代迁移到另一个父代,是否会无意间从数据库表中删除那些子代, 而不 应该 这样 做?
当前使用具有JPA 2.1的EclipseLink 2.6.0。
编辑:
如果Employee仅从相反侧的列表中删除一个实体(因此,在删除该实体后不将其添加到列表中- 不会迁移到另一个父级,而只是删除了),则该对象对应的行也照常从数据库中删除(orphanRemoval = true)但是,当Employee实体(子级)从其本机父级列表中删除后,该实体(子级)被添加到另一个父级列表中时,该行只是被更新(实体的迁移)。
orphanRemoval = true
提供者似乎很聪明,可以检测到孩子从其父母到另一父母的迁移,作为更新。
在Hibernate(最终版4.3.6)和EclipseLink(2.6.0)上都可以看到相同的行为,但是如果它是提供程序特定的行为(不是可移植的),则不能依靠该行为。我在JPA规范中找不到有关此行为的任何信息。
JPA规范中对此进行了记录。
第 3.2.4 节(节选):
应用于实体X的刷新操作的语义如下: 如果X是受管实体,则将其同步到数据库。 对于由X的关系引用的所有实体Y,如果已使用级联元素值Cascade = PERSIST或Cascade = ALL注释了与Y的关系,则对Y应用持久性操作
应用于实体X的刷新操作的语义如下:
第 3.2.2 节(节选):
应用于实体X的persist操作的语义如下: 如果X是已删除的实体,则它将被管理。
应用于实体X的persist操作的语义如下:
orphanRemovalJPA javadoc:
(可选)是否 将删除操作 应用于已从关系中删除的实体,以及是否将删除操作应用于这些实体。
orphanRemovalhibernate文档:
如果一个实体从删除@OneToMany集合或相关实体是由非关联@OneToOne的关联,这种关联的实体可以 标记为删除 ,如果orphanRemoval设置为true。
@OneToMany
@OneToOne
因此,您将雇员E从部门中删除D1,并将其添加到部门中D2。
E
D1
D2
然后,Hibernate将部门D1与数据库同步,发现该部门E不在员工列表中,并标记E为删除。然后,它D2与数据库同步,并将PERSIST操作级联到员工列表(第3.2.4节)。由于E现在位于此列表中,因此级联将应用于此列表,并且Hibernate取消安排删除操作的时间表(第3.2.2节)。
PERSIST
您可能还想看看这个问题。
“如果orphanRemoval设置为true这种关系的反面会发生什么?”
您已经将它设置在反面(反面是声明的那一面mappedBy)。如果你的意思是,如果它被设置在什么 其他 方面(@ManyToOne在这种情况下),那就不是为什么没有在这样的属性意义和的@ManyToOne和@ManyToMany。
mappedBy
@ManyToOne
@ManyToMany