JPA - обновление @OneToMany - PullRequest
       11

JPA - обновление @OneToMany

6 голосов
/ 08 декабря 2011

Предположим, что есть два подразделения: Департамент и Сотрудник, где в одном отделе работают N сотрудников.

В отделении:

@OneToMany(mappedBy = "department", fetch = FetchType.EAGER)
private Collection<Employee> employees = new ArrayList<Employee>();

На сотрудника:

@ManyToOne(fetch = FetchType.EAGER)
private Department department;

Все работает, но я бы хотел добавить сотрудников в отдел без установки обратной связи.Например:

// I will add two employees to a department
department.getEmployees().add(employee1);
department.getEmployees().add(employee2);

// In fact, it is necessary to set the opposite side of the relationship
employee1.setDepartment(department);
employee2.setDepartment(department);

entityManager.merge(department);      
//...

Итак, мой вопрос: есть ли какой-то способ (например, с помощью некоторой аннотации), что JPA поймет, что он должен распространять изменения на другую сторону отношения без явноготот?Другими словами, я хотел бы сделать только это:

department.getEmployees().add(employee1);
department.getEmployees().add(employee2);
entityManager.merge(department);

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 08 декабря 2011

Четкий ответ таков: нет, ваш JPA-провайдер не может автоматически обрабатывать двунаправленные отношения так, как вы это описали.

Однако вы можете реализовать логику для установки двунаправленных ассоциаций в ваших сущностях, возможно, что-то вроде этого:

class Department {

  public void addEmployee(Employee empl) {
    if (empl.getDepartment() != null && !this.equals(empl.getDepartment())) {
      empl.getDepartment().getEmployees().remove(empl);
    }
    empl.setDepartment(this); // use the plain setter without logic
    this.employees.add(empl);
  }
}


class Employee {
  // additional setter method with logic
  public void doSetDepartment(Department dept) {
    if (this.department != null && !this.department.equals(dept)) {
      this.department.getEmployees().remove(this);
    }
    dept.getEmployees().add(this);
    this.department = dept;
  }
}

В этом случае вы должны, однако, убедиться, что ассоциации уже инициализированы, когда объекты обрабатываются вне контекста постоянства, чтобы избежать отложенных исключений init. Это может заставить вас переключиться на активную загрузку для всех ассоциаций, что обычно не является хорошим выбором. Из-за сложности двунаправленных ассоциаций я лично избегаю двунаправленных ассоциаций в сущностях и использую их только тогда, когда для этого есть действительно веские основания.

2 голосов
/ 08 декабря 2011

JPA не будет управлять вашим графом объектов Java для вас. Вы можете либо обновить граф объектов самостоятельно, как и в своем вопросе, либо, я полагаю, вы могли бы перезагрузить все объекты после сохранения.

Я не фанат двунаправленных отношений, потому что они могут запутаться, но если вы должны это сделать, то вы, вероятно, захотите выбрать одну сторону, которая будет "владеющей" стороной отношений. Посмотрите, где говорится о «mappedBy» на этой странице http://www.objectdb.com/java/jpa/entity/fields, чтобы узнать, как это сделать.

Если у вас есть служба, которую вы внедрили, то вы можете предоставить сервисный вызов, который позаботится об управлении такого рода вещами, тогда у вас не будет такой большой возможности забыть об этом в одном месте в вашем коде и делать это правильно в остальных 15 местах.

1 голос
/ 08 декабря 2011

Единственный способ сделать это явно, как вы упомянули.

...