13

假设我们有以下实体:

    @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 中吗?或者在一个带有分离实体的简单控制器方法上做就足够了?

4

2 回答 2

14

问题是我是否应该按如下方式在两侧应用合并,并且避免与级联进行第二次合并?

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

如果这些关系已使用元素值或注释进行注释,则merge操作将级联到关系引​​用的实体。Departmentcascadecascade=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方法。

于 2013-11-19T11:16:39.030 回答
3

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

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

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

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

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

关于如何开始交易/如何开始交易:这取决于交易的类型EntityManager(取决于您获得交易的方式)。在 EJB 中,处理一般情况要容易得多。此外,根据merge 方法的文档,会抛出 TransactionRequiredException if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction

于 2013-11-19T10:40:42.267 回答