问题 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);

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


8090
2017-11-19 10:15


起源

如果您正在与数据库进行交互,则应该在事务中。无论您是否使用JPA,都是如此。通过调用EJB来显式或隐式地启动事务并不重要;他们都会做这个工作。 - Tom Anderson
汤姆安德森说的是 几乎 总是如此。例外情况是,当您进行查找时,您会发现除了以外的锁定 LockModeType.NONE。 - Andrei I


答案:


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

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

merge 操作级联到由关系引用的实体 Department 如果这些关系已被注释 cascade 元素价值 cascade=MERGE 要么 cascade=ALL 注解。

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

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

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


12
2017-11-19 11:16



“管理实体之间的双向关系将根据关系的拥有方(员工)持有的引用来保持。”这是否意味着您必须合并拥有方(员工)?或者您只是将想要应用级联效果的一侧合并? - ChrisGeo
你需要合并你想要应用级联效果的那一面。你需要合并 Department 并且更改将级联到关联的 employees。 - Debojit Saikia
@ChrisGeo:这里有两个独立的规则。首先,哪些对象保存到数据库是由关系上的级联属性决定的。其次,每个对象保存到数据库的状态由拥有方对象的状态决定。所以,如果你合并了 Department,和 employees 属性被标记为级联合并,然后是 Employees将合并。如果是的话 Employees状态是正确的,然后正确的数据将被写入数据库。 - Tom Anderson


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

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

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

与交易的需要有关:是的,您需要合并操作一个活动的事务。摘自JPA 2规范:

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

关于如何开始交易/如何交易交易:它取决于交易的类型 EntityManager (在你如何得到一个的方式)。在EJB中,对于通用情况,处理它更容易。另外,根据文件 合并方法,抛出TransactionRequiredException, if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction


3
2017-11-19 10:40