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

查看:116
本文介绍了如何在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
}

然后我更新现有的这样的

and I update existing ones like this:

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天全站免登陆