JPA更新双向关联

时间:2013-11-19 10:15:47

标签: java hibernate jpa bidirectional-relation

假设我们有以下实体:

    @Entity
    public class Department {

        @OneToMany(mappedBy="department")
        private List<Employee> 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中吗?或者在一个带有分离实体的简单控制器方法上做它就足够了?

2 个答案:

答案 0 :(得分:12)

  

问题是我是否应该按照以下方式对双方进行合并,并且我避免第二次使用级联合并?

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

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

管理实体之间的双向关系将根据关系的拥有方(Employee)持有的引用来保留。开发人员有责任将内存引用保留在拥有方(Employee)上,而保持在反方(Department)上的内容引用在更改时保持一致。因此,使用以下一系列语句,关系将与一个merge

同步到数据库
Employee emp = new Employee();
Department dep = new Department();
emp.setDepartment(dep);
dep.getEmployees().add(emp);
...
entityManager.merge(dep);

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

答案 1 :(得分:3)

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

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

  

托管实体之间的双向关系将保持不变   基于关系所属方的参考。它是   开发人员有责任保留内存中的引用   在拥有方和那些与反方保持一致的方面   当他们改变时彼此相对。在单向一对一的情况下   和一对多的关系,这是开发人员的责任   确保关系的语义得到遵守。[29]

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

  

必须在其中调用persist,merge,remove和refresh方法   具有a的实体管理器的事务上下文   使用事务范围的持久性上下文。如果没有   交易背景,   抛出javax.persistence.TransactionRequiredException。

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