将孩子从其父级迁移到另一个父级时,将orphanRemove设置为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是由客户端提供的分离实体),

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所持有的部门实例不同,则应首先将其从与该Employee相关联的相反侧的当前部门所持有的员工列表(employeeList)中删除,然后再将其添加到所提供的新department所持有的人员列表中。

作为猜测,Employee行应该在从员工所在部门当前引用的员工列表中删除Employee实例时(在触发此操作之前),即在将子级从其父级迁移到另一个父级时,无意中从数据库中删除,子行在被另一个父行采用之前需要从其本机父行中移除,并且该子行被认为是无意中从数据库中移除的(orphanRemoval = true)。

但是,数据库表中的employee行与更新的列值保持不变。除UPDATE语句外,不生成任何DML语句。

我是否可以考虑,以这种方式将子级从其父级迁移到另一个父级,不会无意中从数据库表中删除这些子级,因为它们应该是而不是

目前使用的EclipseLink 2.6.0具有JPA 2.1。


编辑:

如果一个Employee实体只是从相反侧的列表中删除(因此,在它被删除后没有添加到列表中——没有迁移到另一个父实体,而是刚刚被删除),那么它的对应行也像往常一样从数据库中删除(orphanRemoval = true),但该行只是被更新,当CCD_ 14实体(子实体)从其本机父实体的列表中删除后被添加到另一个父实体的名单中时(实体的迁移)。

该提供程序似乎足够聪明,可以检测到孩子从父母迁移到另一个父母,作为更新。

在Hibernate(4.3.6最终版本)和EclipseLink(2.6.0)上可以看到相同的行为,但如果它是特定于提供商的行为(不可移植),则不能依赖它。我在JPA规范中找不到任何关于这种行为的信息。

这在JPA规范中有文档记录。

3.2.4节(摘录):

应用于实体X的flush操作的语义如下如下:

  • 如果X是托管实体,则会将其同步到数据库。
    • 对于由来自X的关系引用的所有实体Y,如果与Y的关系已用级联元素值进行了注释cascade=PERSIST或cascade=ALL,持久操作应用于Y

章节3.2.2(摘录):

应用于实体X的持久化操作的语义如下如下:

  • 如果X是一个已删除的实体,则它变为托管实体

orphanRemoval JPA javadoc:

(可选)是否将移除操作应用于已从关系中删除,并级联删除对这些实体的操作。

orphanRemoval休眠文档:

如果从@OneToMany集合或关联实体从@OneToOne关联中取消引用,这如果orphanRemoval为设置为CCD_ 20。

因此,您将员工E从部门D1中删除,并将她添加到部门D2中。

然后Hibernate将部门D1与数据库同步,发现E不在员工列表中,并将E标记为删除。然后,它将D2与数据库同步,并将PERSIST操作级联到员工列表中(第3.2.4节)。由于E现在在该列表中,级联应用于它,Hibernate取消调度删除操作(第3.2.2节)。

你可能也想看看这个问题。

"如果orphanRemoval在这种关系的相反一侧设置为true,会发生什么?"

您已经将其设置在反面(反面是声明mappedBy的一面)。如果你的意思是,如果它被设置在另一个侧(在这种情况下是@ManyToOne),那么它就没有意义了,这就是为什么@ManyToOne@ManyToMany中没有这样的属性。

相关内容

  • 没有找到相关文章

最新更新