Я пытаюсь понять, почему поведение 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 () и того, как оно связано или не связано с распространением изменения состояния сущности (и связанных с ней сущностей) на БД. Но, тем не менее, в Департаменте нет аннотаций каскадного типа.
РЕДАКТИРОВАТЬ2 Я думаю, что я где-то получаю. Я добавил новый метод, который создает новый отдел («АНГЛИЙСКИЙ»), извлекает сотрудника, как и прежде, с помощью 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();
}
}