在JPA中无状态更新一对多关系的正确方法?

时间:2013-03-25 10:41:22

标签: jpa spring-data-jpa

我有一个用于数据模型的REST接口,它在实体之间具有多个一对多和多对多关系。虽然多对多关系似乎很容易无国籍地管理,但我遇到了一对多的问题。考虑以下一对多关系:

员工:

@ManyToOne
@JoinColumn(name = "Company_id")
private Company company;

公司:

@OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval=true)
public Set<Employee> employees = new HashSet<Employee>();

更新公司时,其员工集合也可能已更新(员工已删除或添加)但由于REST界面仅允许更新公司,因此我无法明确删除或添加员工。

简单地更换集合不起作用,但我发现这似乎有效:

public void setEmployees(Set<Employee> employee) {
  this.employees.clear(); // magic happens here?
  this.employees.addAll(employees);
  for (Iterator<Employee> iterator = employees.iterator(); iterator.hasNext();) {
    Employee employee = (Employee) iterator.next();
    employee.setCompany(this);
  }
} 

这是应该做的,还是有更好的方法?

编辑:事实上以上不起作用!它似乎首先起作用,但随后它会破坏:

Exception in thread "main" java.lang.IllegalStateException: An entity copy was already assigned to a different entity.

我认为这是因为数据库已经包含一组员工,如果任何“旧”员工也是替换集的一部分,他们就会与数据库中的员工发生冲突。

那么更换套装的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

首先确保正确实施等于。根据hibernate规范:http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch04.html#persistent-classes-equalshashcode

我在合并时遇到了类似的问题。基本上我必须获取与公司相关的现有员工。我必须将任何更改合并到现有员工,然后添加任何新员工。

    Query query = em.createQuery("select e from Employee e where e.company = '" + company.getId() + "'");
    Collection<Employee> existingEmployees = new LinkedList<Employee>();
    try{
        Iterables.addAll(existingEmployees, (Collection<Employee>) query.getResultList());
    }
    catch(NoResultException nre){
        //No results
    }

    for(Employee existingEmployee : existingEmployees){
        for(Employee employee : company.getEmployees()){
            if(existingEmployee.name().equals(employee.name())){
                employee.setId(existingEmployee.getId());
            }
            employee.setCompany(company);
        }
    }

答案 1 :(得分:1)

我认为你没有更好的选择来替换现有的集合,只需设置REST响应提供的新集合。