Каскадное поведение для persist () при создании новой сущности против изменения существующей сущности - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь понять, почему поведение 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();
        } 
    }

1 Ответ

0 голосов
/ 12 сентября 2018

Каскадирование в основном определяет операцию, которая должна быть выполнена с базовым объектом, если действие выполняется с текущим объектом.

В вашем случае, поскольку вы не указываете каскадный тип для вашего объекта department вСущность Employee, по умолчанию она установлена ​​на NONE (тип каскада по умолчанию, т.е. при выполнении операции над объектом Employee не будет выполнено никаких действий с объектом Department).Но так как вы указали отношения между Сотрудником и Отделом, если отдел, связанный с Сотрудником, еще не присутствует в базе данных, тогда вы столкнетесь с IllegalStateException.Именно поэтому вам необходимо отдельно persist отделить объект.

Во втором случае, когда вы указываете тип каскада на PERSIST, он автоматически сохранит department вместе с Employee Object.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...