JPA 更新双向关联

假设我们有以下实体:

    @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);

还是合并拥有方就足够了?此外,这些合并是否应该在事务或 EJB 内部进行?或者,在具有分离实体的简单控制器方法上执行此操作就足够了吗?


答案 1

问题是,我是否应该在两端应用合并,如下所示,并且我避免与级联的第二次合并?

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

如果已使用元素值或注释批注了这些关系,则该操作将级联到由这些关系引用的实体。mergeDepartmentcascadecascade=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 方法在其他时间将实体的内存中状态同步到数据库。


答案 2

您有一个持久操作(使用 )。持久化新员工并不意味着该部门也是持久化的(您没有级联),因此由于其他原因(只需尝试并发布异常),它将引发异常。为了避免这种情况,您可以添加一个级联类型,或者同时保留它们(如您在示例中所做的那样)。em.merge()

关于你的问题:唯一考虑的部分是拥有方。在 JPA 2.0 规范中,=> 如下所示:Chapter 3 Entity Operations3.2.4 Syncrhonization to the Database

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

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

当使用具有事务范围的持久性上下文的实体管理器时,必须在事务 con-text 中调用持久化、合并、删除和刷新方法。如果没有 transac- tion 上下文,则会引发 javax.persistence.TransactionRequiredException。

关于如何开始交易/如何对交易进行星形处理:这取决于交易的类型(取决于您如何获得交易的方式)。在 EJB 中,对于一般情况,处理起来要容易得多。此外,根据合并方法的文档,将抛出一个事务需要异常。EntityManagerif invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction


推荐