将 children 从他们的 parent 迁移到另一个 parent 时将 orphanRemoval 设置为 true
Setting orphanRemoval to true while migrating children from their parent to another parent
重要提示: 如果您正在阅读这篇文章 post,请考虑查看 以进行 in-depth 讨论。
这是一个很常见的 practice/situation/requirement,其中一个 parent 的 children 可能会迁移到另一个 parent。如果在这种关系的反面将 orphanRemoval
设置为 true
,会发生什么情况?
以任何简单的 one-to-many 关系为例。
反面(部门):
@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;
在像下面那样合并 operation/action 时(其中 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);
当然,添加和删除员工可能更好done/handled在关联实体中使用防御性link(关系)管理方法。
部门实例由客户提供。它是一个分离的实体。它可以是相同或不同的部门,具体取决于相关客户执行的管理操作。因此,如果客户端提供的部门实例与当前 Employee
持有的部门实例不同,则应首先将其从当前 employeeList
持有的员工列表中删除=63=]old 部门在与 Employee
相关联的反面,然后将其添加到新 department
提供的员工列表中。
作为猜测,Employee
行应该从数据库中无意中删除,同时从员工部门当前引用的员工列表中删除 Employee
实例 - 旧部门(之前此操作已被触发)即,在将 child 从其 parent 迁移到另一个 parent 时,需要先从其原生 parent 中删除 child被另一个 parent 采用,并且 child 行应该被无意中从数据库中删除 (orphanRemoval = true
)。
但是,数据库中的员工行 table 保持不变,并具有更新后的列值。除 UPDATE
语句外,没有生成任何 DML 语句。
我可以考虑一下,以这种方式将 children 从他们的 parent 迁移到另一个 parent,不会无意中从数据库中删除那些 children table 他们应该不是?
目前正在使用带有 JPA 2.1 的 EclipseLink 2.6.0。
编辑:
如果 Employee
实体仅从相反侧的列表中删除(因此,在删除后未添加到列表中 - 未迁移到另一个 parent 而只是删除),然后它的相应行也像往常一样从数据库中删除(orphanRemoval = true
)但是当一个Employee
实体(child)被添加到另一个[=的列表时,该行被简单地更新了85=] 从其原生列表中删除后 parent (实体迁移)。
提供商似乎足够聪明,可以检测 children 从他们的 parent 迁移到另一个 parent,作为更新。
在 Hibernate(4.3.6 final)和 EclipseLink(2.6.0)上可以看到相同的行为,但不能依赖它,如果它是提供者特定的行为(不是 portable) .我在 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.
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 if orphanRemoval
is
set to true
.
因此,您将员工 E
从部门 D1
中删除并将她添加到部门 D2
。
Hibernate 然后将部门 D1
与数据库同步,发现 E
不在员工列表中并标记 E
以进行删除。然后它将 D2
与数据库同步,并将 PERSIST
操作级联到员工列表(第 3.2.4 节)。由于 E
现在在此列表中,因此级联应用于它并且 Hibernate 取消安排删除操作(第 3.2.2 节)。
您可能还想看看这个 question。
"What happens, if orphanRemoval
is set to true
on the inverse side of such relationships?"
你已经设置反面了(反面就是声明mappedBy
的那一面)。如果你的意思是如果它被设置在 other 一侧(在这种情况下为 @ManyToOne
),那么它就没有意义,这就是为什么 @ManyToOne
和 @ManyToMany
.
重要提示: 如果您正在阅读这篇文章 post,请考虑查看
这是一个很常见的 practice/situation/requirement,其中一个 parent 的 children 可能会迁移到另一个 parent。如果在这种关系的反面将 orphanRemoval
设置为 true
,会发生什么情况?
以任何简单的 one-to-many 关系为例。
反面(部门):
@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;
在像下面那样合并 operation/action 时(其中 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);
当然,添加和删除员工可能更好done/handled在关联实体中使用防御性link(关系)管理方法。
部门实例由客户提供。它是一个分离的实体。它可以是相同或不同的部门,具体取决于相关客户执行的管理操作。因此,如果客户端提供的部门实例与当前 Employee
持有的部门实例不同,则应首先将其从当前 employeeList
持有的员工列表中删除=63=]old 部门在与 Employee
相关联的反面,然后将其添加到新 department
提供的员工列表中。
作为猜测,Employee
行应该从数据库中无意中删除,同时从员工部门当前引用的员工列表中删除 Employee
实例 - 旧部门(之前此操作已被触发)即,在将 child 从其 parent 迁移到另一个 parent 时,需要先从其原生 parent 中删除 child被另一个 parent 采用,并且 child 行应该被无意中从数据库中删除 (orphanRemoval = true
)。
但是,数据库中的员工行 table 保持不变,并具有更新后的列值。除 UPDATE
语句外,没有生成任何 DML 语句。
我可以考虑一下,以这种方式将 children 从他们的 parent 迁移到另一个 parent,不会无意中从数据库中删除那些 children table 他们应该不是?
目前正在使用带有 JPA 2.1 的 EclipseLink 2.6.0。
编辑:
如果 Employee
实体仅从相反侧的列表中删除(因此,在删除后未添加到列表中 - 未迁移到另一个 parent 而只是删除),然后它的相应行也像往常一样从数据库中删除(orphanRemoval = true
)但是当一个Employee
实体(child)被添加到另一个[=的列表时,该行被简单地更新了85=] 从其原生列表中删除后 parent (实体迁移)。
提供商似乎足够聪明,可以检测 children 从他们的 parent 迁移到另一个 parent,作为更新。
在 Hibernate(4.3.6 final)和 EclipseLink(2.6.0)上可以看到相同的行为,但不能依赖它,如果它是提供者特定的行为(不是 portable) .我在 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.
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
.
因此,您将员工 E
从部门 D1
中删除并将她添加到部门 D2
。
Hibernate 然后将部门 D1
与数据库同步,发现 E
不在员工列表中并标记 E
以进行删除。然后它将 D2
与数据库同步,并将 PERSIST
操作级联到员工列表(第 3.2.4 节)。由于 E
现在在此列表中,因此级联应用于它并且 Hibernate 取消安排删除操作(第 3.2.2 节)。
您可能还想看看这个 question。
"What happens, if orphanRemoval
is set to true
on the inverse side of such relationships?"
你已经设置反面了(反面就是声明mappedBy
的那一面)。如果你的意思是如果它被设置在 other 一侧(在这种情况下为 @ManyToOne
),那么它就没有意义,这就是为什么 @ManyToOne
和 @ManyToMany
.