假设我们有以下实体:
@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中吗?或者在一个带有分离实体的简单控制器方法上做它就足够了?
答案 0 :(得分:12)
问题是我是否应该按照以下方式对双方进行合并,并且我避免第二次使用级联合并?
您可以使用级联注释元素将操作的效果传播到关联实体。级联功能最常用于父子关系。
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#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
。