假设我们有以下实体:
@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 中进行?还是在具有分离实体的简单控制器方法上执行此操作就足够了?
问题是我是否应该按如下方式在两侧应用合并,并且我是否应该避免使用级联进行第二次合并?
可以使用级联注释元素将操作的效果传播到关联的实体。级联功能最常用于父子关系。
如果这些关系已使用 cascade
元素值cascade=MERGE
或cascade=ALL
注释进行了批注,则merge
操作将级联到Department
关系引用的实体。
托管实体之间的双向关系将根据关系的拥有方(Employee)
持有的引用进行保留。开发人员有责任使保存在拥有端的内存中引用(Employee)
和在反向侧保存的内存中引用在更改时(Department)
彼此一致。因此,通过以下一系列语句,关系将通过单个merge
同步到数据库:
Employee emp = new Employee();
Department dep = new Department();
emp.setDepartment(dep);
dep.getEmployees().add(emp);
...
entityManager.merge(dep);
这些更改将在事务提交时传播到数据库。当事务处于活动状态时,也可以使用 EntityManager#flush 方法将实体的内存中状态同步到数据库。
你有一个持久操作(用em.merge()
(。保留新员工并不意味着该部门也保留(您没有级联(,因此它会因为其他原因而引发异常(只需尝试并发布异常(。为了避免这种情况,您可以添加级联类型,或者同时保留它们(如示例中所做的那样(。
关于你的问题:唯一考虑的部分是拥有方。在 JPA 2.0 规范中,Chapter 3 Entity Operations
=> 3.2.4 Syncrhonization to the Database
如下:
托管实体之间的双向关系将保持不变 基于关系的拥有方持有的参考资料。是的 开发人员有责任保留内存中的引用 在拥有方和持有的反方一致 彼此改变时。在单向一对一的情况下 和一对多关系,这是开发商的责任 以确保遵守关系的语义。[注二九]
与事务的需要有关:是的,合并操作需要活动事务。摘自 JPA 2 规范:
必须在 当实体经理具有 使用事务范围的持久性上下文。如果没有 交易上下文, javax.persistence.TransactionRequiredException 被抛出。
关于交易的开始方式/你如何盯着交易:这取决于EntityManager
的类型(你如何获得交易的方式(。在 EJB 中,对于一般情况,处理它要容易得多。此外,根据合并方法的文档,抛出了一个 TransactionRequiredException,if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction
。