Hibernate 当某个实体的父集合';合并时,实体中的s引用已设置为null?
反向侧(部门): 合并由客户提供的Hibernate 当某个实体的父集合';合并时,实体中的s引用已设置为null?,hibernate,jpa,merge,eclipselink,Hibernate,Jpa,Merge,Eclipselink,反向侧(部门): 合并由客户提供的员工实体的方法,该实体中包含空的部门: public Employee update(Employee employee) { Department department = employee.getDepartment(); if (department == null) { Employee managedEmployee = entityManager.find(Employee.class, employee.getEm
员工
实体的方法,该实体中包含空的部门
:
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);
}
}
提供的员工
是分离的实体。假设部门
对于员工
是可选的,因此存在空外键(因此,在后端系统中指定了删除集空)
当提供的员工
不包含部门
时,是否有必要从关系反面的员工列表(部门
)中明确删除上述更新()方法所示的员工
实体(因为客户端在编辑员工
实体时已将其设置为null),然后再合并提供的员工
实体
我认为,提供者会将员工
引用保留在员工列表中关系的反面,否则会挂起。由于关联的所有者方位于员工
实体,因此不必从员工部门
的集合中删除该员工
您可以删除该部分代码
还要注意,如果employee是一个已删除的实体实例,则merge
方法将抛出一个IllegalArgumentException
。因此,您可能无法简单地删除find(employee)从您的代码中删除部分,或者您可以捕获重新抛出EntityNotFoundException
的异常,但所有这些都取决于您的代码逻辑
添加官方来源
引用JPA 2规范()部分同步到数据库:
受管实体之间的双向关系将基于关系的拥有方持有的引用而持久化。开发人员有责任保持拥有方持有的内存中引用和反向持有的内存中引用在发生冲突时保持一致更改。在单向一对一和一对多关系的情况下,开发人员有责任确保遵守关系的语义。
尤其重要的是,要确保对关系的反向端所做的更改会在所属端产生适当的更新,以确保更改在与数据库同步时不会丢失
应用程序需要维护双向关系的两侧以进行缓存。如果不维护集合,则在重新加载之前,它将与数据库不同步
它“可能”不是必需的,但这是提供商和缓存的功能。如果部门被缓存(在当前EntityManager或二级缓存中),并且列表已获取,则它将不知道更改。在这种情况下,您必须使用刷新选项或缓存无效选项强制重新加载实体。直接维护列表通常更容易。如果担心性能,可以在调用re之前验证列表是否已加载移动,但并不总是需要(EclipseLink的更改跟踪可以允许在不加载集合的情况下进行修改)
“删除时设置为空”在JPA之外,我不知道如何告诉提供者这是在关系上设置的。将Employee.department关系设置为null并合并没有多大意义,因为JPA随后会尝试将外键更新为null,这是不必要的。我不建议使用它,但如果必须,请刷新/使外键无效缓存中的Employee,而不是将关系更新为null。有一个具有相同内容的问题,但我意外忘记删除cascade=CascadeType。关系的反面的ALL
和orphanRemoving=true
改变了问题的整个定义。您如何处理底层问题update
方法的作用?是否使用扩展持久性上下文传播?是否在调用update
方法之前和/或之后检索和/或修改重要的实体实例?如何执行?它是EJB中事务范围的EntityManager
(默认为@PersistenceContext(type=PersistenceContextType.TRANSACTION)
。@PersistenceContext(type=PersistenceContextType.EXTENDED)
不适用于无状态会话bean。对于此类CRUD操作,使用详细的有状态会话bean保持状态是绝对多余的。JSF使用EJB,在需要时,根据业务需求修改实体,并重新提交到适当的EJB,以便将其传播到底层数据库。我不确定它是如何关联的。因此,您使用的是容器管理的事务(意味着您从不显式地开始或提交事务),并且直接调用update
方法(通过注入的EJB)只有JSF支持beans逻辑,对吗?是的,绝对如前所述。但它与如何维护关联相关-双向/单向?为什么不需要它,而JPA需要在删除实体之前从其反向集合中显式删除实体(即entityManager.remove(entity)
)?对于这些代码,不需要,因为关联由员工表上的字段(部门id
)表示。提交更改后(将某些部门id
设置为空)要检索部门的employees集合,提供程序将查找具有反向集合中特定部门idIf的employees元组
@JoinColumn(name = "department_id", referencedColumnName = "department_id")
@ManyToOne(fetch = FetchType.LAZY)
private Department 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);
}
}