如何在 Spring JPA 中保存引用现有实体的新实体? [英] How to save a new entity that refers existing entity in Spring JPA?

查看:20
本文介绍了如何在 Spring JPA 中保存引用现有实体的新实体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象以下模型:

员工:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "employee_project", joinColumns = @JoinColumn(name = "Emp_Id"), inverseJoinColumns = @JoinColumn(name = "Proj_id"))
private Set<Project> projects = new HashSet<Project>();

项目:

@ManyToMany(mappedBy = "projects")
private Set<Employee> employees = new HashSet<Employee>();

现在,如果我创建一个引用现有项目的新员工并尝试保留该员工,我会收到一个错误:

Now if I create a new employee that refers to an existing project and try to persist that employee, I get an error:

detached entity passed to persist: Project

我按如下方式创建员工:

I create the employee as follows:

public void createNewEmployee(EmployeeDTO empDTO) {

  Employee emp = new Employee();
  // add stuff from DTO, including projects

  repository.saveAndFlush(emp);  // FAILS
}

我像这样更新现有的:

public void updateEmployee(EmployeeDTO empDTO) {

   Employee emp = repository.findOne(empDTO.getId());
   // set stuff from DTO, including projects

   repository.saveAndFlush(emp);  // WORKS!
}

推荐答案

我猜您是在与存储库交互,而没有适当地扩展事务边界.默认情况下,事务(以及会话)边界位于存储库方法级别.这会导致 Project 实例与 EntityManager 分离,因此它无法包含在持久操作中.

I guess you're interacting with the repository without expanding the transaction boundaries appropriately. By default, the transaction (and thus session) boundary is at the repository method level. This causes the Project instance to be detached from the EntityManager, so that it cannot be included in a persist operation.

这里的解决方案是将事务边界扩展到客户端:

The solution here is to extend the transaction boundary to the client:

@Component
class YourRepositoryClient {

  private final ProjectRepository projects;
  private final EmployeeRepository employees;

  // … constructor for autowiring

  @Transactional
  public void doSomething() {
    Project project = projects.findOne(1L);
    Employee employee = employees.save(new Employee(project));
  }
}

这种方法使 Project 实例保持为托管实体,从而为正确处理的新 Employee 实例执行持久化操作.

This approach causes the Project instance stay a managed entity and thus the persist operation to be executed for the fresh Employee instance being handled correctly.

两个存储库交互的不同之处在于,在第二种情况下,您将拥有一个分离的实例(已被持久化,有一个 id 集),而在第一个示例中,您有一个完全非托管的实例,它没有有一个 id 集.id 属性是使存储库区分调用 persist(…)merge(…) 的原因.因此,第一种方法将导致触发 persist(...),第二种方法将导致 merge(...).

The difference with the two repository interactions is that in the second case you'll have a detached instance (has already been persisted, has an id set), where as in the first example you have a completely unmanaged instances that does not have an id set. The id property is what causes the repository to differentiate between calling persist(…) and merge(…). So the first approach will cause a persist(…) to be triggered, the second will cause a merge(…).

这篇关于如何在 Spring JPA 中保存引用现有实体的新实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆