JPA更新双向关联

让我们假设我们有以下实体:

@Entity public class Department { @OneToMany(mappedBy="department") private List employees; } @Entity public class Employee { @ManyToOne private Department department } 

在更新中我们需要维护关系的两个方面,这是可以理解的,如下所示:

 Employee emp = new Employee(); Department dep = new Department(); emp.setDepartment(dep); dep.getEmployees().add(emp); 

一切都很好,直到现在。 问题是我应该如下所示在双方应用合并,并且我避免第二次合并级联?

 entityManager.merge(emp); entityManager.merge(dep); 

或者正在合并拥有方? 这些合并也应该发生在Transaction或EJB中吗? 或者在一个带有分离实体的简单控制器方法上做它就足够了?

问题是我应该如下所示在双方应用合并,并且我避免第二次合并级联?

您可以使用级联注释元素将操作的效果传播到关联实体。 级联function最常用于父子关系。

如果这些关系已使用cascade元素值cascade=MERGEcascade=ALL注释进行注释,则merge操作将级联到由Department关系引用的实体。

管理实体之间的双向关系将基于关系的拥有方(Employee)持有的引用而持久化。 开发人员有责任将内存引用保留在拥有方(Employee)和反向(Department)保持在更改时保持一致。 因此,使用以下一系列语句,关系将通过单个merge同步到数据库:

 Employee emp = new Employee(); Department dep = new Department(); emp.setDepartment(dep); dep.getEmployees().add(emp); ... entityManager.merge(dep); 

这些更改将在事务提交时传播到数据库。 当事务处于活动状态时,使用EntityManager#flush方法,实体的内存中状态也可以在其他时间同步到数据库。

你有一个持久的操作(使用em.merge() )。 坚持新员工并不意味着部门也是持久的(你没有级联),所以它会因为另一个原因而抛出exception(只需尝试并发布exception)。为了避免这种情况,你要么添加一个级联类型,或坚持他们两个(正如你在你的例子中所做的那样)。

关于你的问题:考虑的唯一部分是拥有方。 在JPA 2.0规范中, Chapter 3 Entity Operations => 3.2.4 Syncrhonization to the Database是以下内容:

管理实体之间的双向关系将基于关系所属方所持有的引用而持久化。 开发人员有责任保持内存引用保持在拥有方,而保持在反方的引用在更改时保持一致。 在单向一对一和一对多关系的情况下,开发人员有责任确保遵守关系的语义。[29]

与事务需求相关 :是的,您需要将合并操作作为活动事务。 摘自JPA 2规范:

当使用具有事务范围持久性上下文的实体管理器时,必须在事务环境中调用persist,merge,remove和refresh方法。 如果没有事务上下文,则抛出javax.persistence.TransactionRequiredException。

关于如何启动事务/如何设置事务:它取决于EntityManager的类型(关于如何获取事务的方式)。 在EJB中,对于通用情况,处理它更容易。 此外,根据merge方法的文档, if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transactionif invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction抛出TransactionRequiredException。