Каскадное поведение для persist() при создании новой сущности против изменения существующей сущности
Я пытаюсь понять, почему поведение persist() отличается от ManyToOne в случаях, во-первых, сохранения новой сущности и, во-вторых, изменения этой сущности. В моей тестовой настройке сотрудник имеет однонаправленный ManyToOne с отделом; От Департамента нет никаких отношений с сотрудником. Для теста у меня нет никаких каскадных аннотаций в поле Отдел в Employee.
Я обнаружил, что при создании Employee я должен вызывать em.persist (dept), в противном случае экземпляр dept не сохраняется, и я получаю исключение. Итак, я вызываю em.persist (dept), чтобы сущность dept сохранялась. Мой следующий тест - это фиксация и запуск новой транзакции, получение сущности сотрудника с помощью em.find(), изменение имени dept.name и сохранение сотрудника. Я обнаружил, что изменения в отделе сохраняются, несмотря на то, что каскадных аннотаций в области "Сотрудник" в Employee нет.
Почему это? Почему изменения в отделе сохраняются (через em.persist(emp)) в БД без каскада в Отделе, но создание отдела не сохраняется при первом сохранении сотрудника? Что мне не хватает? Кстати, для ясности, в конце теста изменение названия отдела (ДАЛЬНЕЙШИЕ МАТЫ) сохраняется. Благодарю.
РЕДАКТИРОВАТЬ Я только что прочитал, что "Вы можете вызвать этот метод (persist()) на уже постоянном экземпляре, и ничего не происходит" по адресу https://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate. Я думаю, это означает, что в changeDept() мой вызов persist() после find () является избыточным, поэтому я удалил его, и результат тот же. Таким образом, это заставляет меня думать, в дополнение ко многим недоразумениям, одним из них может быть мое понимание persist() и того, как оно связано или не связано с распространением изменения состояния сущности (и связанных с ней сущностей) на БД. Но, тем не менее, в Департаменте нет аннотаций каскадного типа.
EDIT2 Я думаю, что я где-то получаю. Я добавил новый метод, который создает новый отдел ("АНГЛИЙСКИЙ"), извлекает сотрудника, как и раньше, с помощью find (), устанавливает отдел сотрудника в новый отдел и выполняет коммит. Я получаю (к счастью, как и ожидалось) исключение:
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
Это исключение не происходит, если я помещаю PERSIST cascadeType в поле Department. Таким образом, очевидно, что постоянство относится к сохранению новых сущностей; это не относится к распространяющимся изменениям к существующим объектам. Остается вопрос, является ли это поведением по умолчанию (то есть без указания какого-либо типа cascadeType) для распространения изменений на связанные объекты)? Я полагаю, это должно быть.
@Entity
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private double salary;
@ManyToOne
private Department department;
...
}
Deparment:
@Entity
public class Department {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
..
}
методы:
static void setupData() {
try {
em.getTransaction().begin();
Department dept = new Department();
dept.setName("MATHS");
...
Employee emp2 = new Employee("Darth Vader", 10003, dept);
em.persist(emp2);
em.persist(dept); //needed without cascadeType=PERSIST on Department
em.getTransaction().commit();
} catch (Exception e) {
logger.error("oops: " + e);
e.printStackTrace();
em.getTransaction().rollback();
}
}
static void changeDept() {
try {
em.clear();
em.getTransaction().begin();
Employee emp1 = em.find(Employee.class, 2);
logger.info("emp1:" + emp1);
Department dept = emp1.getDepartment();
dept.setName("FURTHER MATHS");
em.persist(emp1);
em.getTransaction().commit();
} catch (Exception e) {
logger.error("oops: " + e);
e.printStackTrace();
em.getTransaction().rollback();
}
}
1 ответ
Каскадирование в основном определяет операцию, которая должна быть выполнена на базовом объекте, если действие выполняется на текущем объекте.
В вашем случае, так как вы не указываете какой-либо каскадный тип на вашем department
объект в Employee
субъект, по умолчанию устанавливается NONE
(тип каскада по умолчанию, т.е. при выполнении операции над объектом Employee не будет предпринято никаких действий). Но так как вы указали отношения между Сотрудником и Отделом, если отдел, связанный с Сотрудником, еще не присутствует в базе данных, тогда вы столкнетесь IllegalStateException
, Именно поэтому вам нужно отдельно persist
Департамент объекта.
Во втором случае, когда вы упоминаете каскадный тип PERSIST
затем он автоматически сохранит department
вместе с Employee
Объект.