【问题标题】:Correct way to statelessly update a one-to-many relationship in JPA?在 JPA 中无状态更新一对多关系的正确方法?
【发布时间】:2013-03-25 10:41:21
【问题描述】:

我有一个数据模型的 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.

我假设发生这种情况是因为数据库已经包含一组员工,如果任何“旧”员工也是替换组的一部分,它们会与数据库中的员工发生冲突。

那么什么才是正确的替换集合的方法呢?

【问题讨论】:

  • 您能否详细解释一下您所说的我无法明确删除或添加员工 并举一些例子?
  • 好吧,因为它是一个 REST 接口,所以我只收到一个带有员工集合的公司的 PUT 请求,这可能已经改变了。获取该集合的持久版本并找出哪些员工已被删除或添加,以便我可以显式调用 add() 和 remove() 似乎更加复杂。

标签: jpa spring-data-jpa


【解决方案1】:

首先确保正确实施equals。根据休眠规范: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);
        }
    }

【讨论】:

  • 好点。事实上,我根本没有实现 equals 和 hashcode 方法,但不知何故,代码大部分时间仍然有效。这是让我烦恼的一件事 - 有时它会一直失败,有时无论我修改多少次员工集,我都无法重现这种情况。
  • 这可能就是使用 JPA 带来的奇迹。
  • 所以,这意味着,在关系中(在这种情况下为 oneToMany),您必须要么使用集合(迭代、更新和合并),要么完全删除旧集合并放入新集合。
【解决方案2】:

我认为您没有更好的选择,然后替换现有集合并简单地设置 REST 响应提供的新集合。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 2021-09-14
    • 2020-11-11
    • 2022-01-10
    • 2016-07-02
    • 1970-01-01
    相关资源
    最近更新 更多