是否需要从其反向集合中删除一个实体,当其父项的引用在合并时已在实体中设置为 null 时?
Is it required to remove an entity from its inverse collection, when its parent's reference is already set to null in the entity while merging?
反面(部门):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private List<Employee> employeeList = new ArrayList<Employee>(0);
拥有方(员工):
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
合并由客户端提供的 Employee
实体的方法,其中包含空 Department
:
public Employee update(Employee employee) {
Department department = employee.getDepartment();
if (department == null) {
Employee managedEmployee = entityManager.find(Employee.class, employee.getEmployeeId());
// Obtain the original Employee entity which may still have its Department intact.
if (managedEmployee == null) {
throw new EntityNotFoundException();
}
Department managedDepartment = managedEmployee.getDepartment();
if (managedDepartment != null) {
managedEmployee.getDepartment().getEmployeeList().remove(managedEmployee);
// Removing an Employee entity from the list on the inverse side,
// since it will no longer be pointing to Employee after Employee is merged.
}
return entityManager.merge(employee);
}
}
所提供的 Employee
是一个分离的实体。假设 Department
对于 Employee
是可选的,因此有一个空外键(因此, ON DELETE SET NULL
在后端系统中指定)。
当在合并提供的 Employee
实体之前,提供的 Employee
不包含 Department
(因为它在编辑 Employee
实体时已被客户端设置为空)?
我认为,提供者会保留关系另一端员工列表中的 Employee
引用,否则将悬空。
因为关联的所有者端在 Employee
实体上,所以没有必要从雇员 Department
的集合中删除雇员。
您可以删除那部分代码。
另请注意,如果员工是已删除的实体实例,merge
方法将抛出 IllegalArgumentException
。所以也许你不能简单地从你的代码中删除 find(employee) 部分,或者你可以捕获异常重新抛出 EntityNotFoundException
但这一切都取决于你代码逻辑。
添加官方来源
引自 JPA 2 规范 (JSR-338) 部分 同步到数据库:
Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship. It is the developer’s responsibility to keep the in-memory references held on the owning side and those held on the inverse side consistent with each other when they change. In the case of unidirectional one-to-one and one-to-many relationships, it is the developer’s responsibility to insure that the semantics of the relationships are adhered to.
It is particularly important to ensure that changes to the inverse side of a relationship result in appropriate updates on the owning side, so as to ensure the changes are not lost when they are synchronized to the database.
应用程序需要维护缓存的双向关系的双方。如果不维护集合,它将与数据库不同步,直到重新加载。
它 'might' 不是必需的,但这将是您的提供程序和缓存的功能。如果 Department 被缓存(在当前 EntityManager 或二级缓存中),并且列表被提取,那么它不会知道变化。在这种情况下,您将不得不使用刷新选项或缓存失效选项强制重新加载实体。直接维护列表通常要容易得多。如果您担心性能,您可以在调用 remove 之前验证列表是否已经加载,但这并不总是需要的(EclipseLink 的更改跟踪可以允许在不加载集合的情况下进行修改)。
"ON DELETE SET NULL" 在 JPA 之外,我不知道有什么方法可以告诉提供者这是在关系上设置的。将 Employee.department 关系设置为 null 并合并没有多大意义,因为 JPA 然后会尝试将外键更新为 null,这是不必要的。我不建议使用它,但如果必须使用,refresh/invalidate 缓存中的 Employee 而不是将关系更新为 null。
反面(部门):
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private List<Employee> employeeList = new ArrayList<Employee>(0);
拥有方(员工):
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
合并由客户端提供的 Employee
实体的方法,其中包含空 Department
:
public Employee update(Employee employee) {
Department department = employee.getDepartment();
if (department == null) {
Employee managedEmployee = entityManager.find(Employee.class, employee.getEmployeeId());
// Obtain the original Employee entity which may still have its Department intact.
if (managedEmployee == null) {
throw new EntityNotFoundException();
}
Department managedDepartment = managedEmployee.getDepartment();
if (managedDepartment != null) {
managedEmployee.getDepartment().getEmployeeList().remove(managedEmployee);
// Removing an Employee entity from the list on the inverse side,
// since it will no longer be pointing to Employee after Employee is merged.
}
return entityManager.merge(employee);
}
}
所提供的 Employee
是一个分离的实体。假设 Department
对于 Employee
是可选的,因此有一个空外键(因此, ON DELETE SET NULL
在后端系统中指定)。
当在合并提供的 Employee
实体之前,提供的 Employee
不包含 Department
(因为它在编辑 Employee
实体时已被客户端设置为空)?
我认为,提供者会保留关系另一端员工列表中的 Employee
引用,否则将悬空。
因为关联的所有者端在 Employee
实体上,所以没有必要从雇员 Department
的集合中删除雇员。
您可以删除那部分代码。
另请注意,如果员工是已删除的实体实例,merge
方法将抛出 IllegalArgumentException
。所以也许你不能简单地从你的代码中删除 find(employee) 部分,或者你可以捕获异常重新抛出 EntityNotFoundException
但这一切都取决于你代码逻辑。
添加官方来源
引自 JPA 2 规范 (JSR-338) 部分 同步到数据库:
Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship. It is the developer’s responsibility to keep the in-memory references held on the owning side and those held on the inverse side consistent with each other when they change. In the case of unidirectional one-to-one and one-to-many relationships, it is the developer’s responsibility to insure that the semantics of the relationships are adhered to. It is particularly important to ensure that changes to the inverse side of a relationship result in appropriate updates on the owning side, so as to ensure the changes are not lost when they are synchronized to the database.
应用程序需要维护缓存的双向关系的双方。如果不维护集合,它将与数据库不同步,直到重新加载。
它 'might' 不是必需的,但这将是您的提供程序和缓存的功能。如果 Department 被缓存(在当前 EntityManager 或二级缓存中),并且列表被提取,那么它不会知道变化。在这种情况下,您将不得不使用刷新选项或缓存失效选项强制重新加载实体。直接维护列表通常要容易得多。如果您担心性能,您可以在调用 remove 之前验证列表是否已经加载,但这并不总是需要的(EclipseLink 的更改跟踪可以允许在不加载集合的情况下进行修改)。
"ON DELETE SET NULL" 在 JPA 之外,我不知道有什么方法可以告诉提供者这是在关系上设置的。将 Employee.department 关系设置为 null 并合并没有多大意义,因为 JPA 然后会尝试将外键更新为 null,这是不必要的。我不建议使用它,但如果必须使用,refresh/invalidate 缓存中的 Employee 而不是将关系更新为 null。