Каскадное поведение для 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 Объект.

Другие вопросы по тегам