JPA, обновляющая двунаправленную ассоциацию

Предположим, что мы имеем следующие Сущности:

    @Entity
    public class Department {

        @OneToMany(mappedBy="department")
        private List<Employee> employees;
    }

    @Entity
    public class Employee {

        @ManyToOne
        private Department department
    }

В обновлении понятно, что нам необходимо поддерживать обе стороны отношения следующим образом:

Employee emp = new Employee();
Department dep = new Department();
emp.setDepartment(dep);
dep.getEmployees().add(emp);

Все до сих пор. Вопрос в том, следует ли применять слияние с обеих сторон следующим образом, а я избегаю второго слияния с каскадом?

entityManager.merge(emp);
entityManager.merge(dep);

Или сливается с собственной стороной? Также должны ли эти слияния произойти внутри транзакции или EJB? Или сделать это по простому методу контроллера с отдельными объектами достаточно?

Ответ 1

Вопрос в том, следует ли применять слияние с обеих сторон следующим образом, а я избегаю второго слияния с каскадом?

Вы можете использовать элемент аннотации каскада для распространения эффекта операции на связанные объекты. Каскадная функциональность наиболее часто используется в отношениях родитель-потомок.

Операция merge каскадируется для объектов, на которые ссылаются отношения из Department, если эти отношения были аннотированы с помощью аннотации элемента cascade cascade=MERGE или cascade=ALL.

Двунаправленные отношения между управляемыми объектами будут сохраняться на основе ссылок, принадлежащих стороне-стороне (Employee) отношения. Ответственность разработчиков заключается в том, чтобы сохранить в памяти ссылки, хранящиеся на стороне пользователя (Employee), и те, которые находятся на обратной стороне (Department), согласованы друг с другом, когда они меняются. Таким образом, с помощью ниже ряда операторов связь будет синхронизирована с базой данных с помощью одного merge:

Employee emp = new Employee();
Department dep = new Department();
emp.setDepartment(dep);
dep.getEmployees().add(emp);
...
entityManager.merge(dep);

Эти изменения будут переданы в базу данных при совершении транзакции. Состояние в памяти в сущности может быть синхронизировано с базой данных в другое время, когда транзакция активна с помощью метода EntityManager # flush.

Ответ 2

У вас есть операция persist (сделана с помощью em.merge()). Сохранение нового сотрудника не означает, что отдел также сохраняется (у вас нет каскадирования), поэтому он будет генерировать исключение по другой причине (просто попробуйте и опубликуйте исключение). Чтобы этого избежать, вы либо добавляете каскадный тип, или сохраняйте их оба (как вы сделали в своем примере).

О вашем вопросе: единственная рассматриваемая часть будет принадлежать стороне. В спецификации JPA 2.0 Chapter 3 Entity Operations = > 3.2.4 Syncrhonization to the Database следует следующее:

Двунаправленные отношения между управляемыми объектами будут сохраняться основанные на ссылках, принадлежащих владелической стороне отношений. это ответственность разработчиков за сохранение содержащихся в памяти ссылок на стороне обладателя и тех, которые находятся на обратной стороне, согласующейся с друг друга, когда они меняются. В случае однонаправленного одностороннего и отношения "один ко многим", это ответственность разработчиков чтобы гарантировать соответствие семантики отношений. [29]

Связано с необходимостью транзакции: да, для операции слияния требуется активная транзакция. Выдержка из спецификации JPA 2:

Методы persist, merge, remove и refresh должны быть вызваны внутри контекст транзакции, когда менеджер объекта с контекст постоянной транзакции. Если нет контекста трансакции, javax.persistence.TransactionRequiredException выбрано.

О том, как запущена транзакция/как вы начинаете транзакцию: она зависит от типа EntityManager (как вы его получите). В EJB гораздо проще справиться с этим в общих ситуациях. Кроме того, согласно документации метода слияния генерируется исключение TransactionRequiredException, if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction.