Гибернация слияния с сохранением. Были ли изменения? - PullRequest
2 голосов
/ 27 января 2020

У меня было приложение со следующим кодом, которое работало просто отлично, пока я не обновил hibernate (5.3.2 до 5.4.10)

    List<UserRole> roles = entity.getRoles();
    for(UserRole r : roles) {
        Em.get().remove(r);
    }
    roles.clear();

    for(RoleEnum r : selectedRoles) {
        UserRole role = new UserRole(entity, r);
        Em.get().persist(role);
    }

    Em.get().merge(entity);
    Em.get().flush();

Итак, я начал получать исключение

Причина: org.hibernate.TransientPropertyValueException: объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом: WEBPIECESxPACKAGE.base.libs.UserRole.user -> WEBPIECESxPACKAGE.base.libs.UserDbo

Это произойдет, когда я «добавлю» новую сущность пользователя. Если я отредактирую старого пользователя (он использует тот же самый точный код), то все будет в порядке.

Вместо этого я изменил на Em.get (). Persist (entity), и это работает для добавления нового объекта в БД и для редактирования старого.

НО в документации по-прежнему говорится, что старый JPA / hibernate использовал для сохранения, то есть

@ выдает исключение EntityExistsException, если объект уже существует.

Все ли сейчас используют функцию persist в качестве функции добавления или редактирования? (ie. Иметь одну функцию, которая сохраняет или редактирует, как мне на самом деле все равно, что очень и очень хорошо, и Hibernate может определить по существующему идентификатору БД или нет, является ли это добавлением или редактированием, поэтому нет причин не делать этого. есть один звонок для обоих).

спасибо, Дин

1 Ответ

1 голос
/ 08 февраля 2020

Возможный дубликат Обновление против слияния

Что здесь происходит: Режим редактирования:

List<UserRole> roles = entity.getRoles(); //Gets Existing Roles from DB
for(UserRole r : roles) {
    Em.get().remove(r); //Removes Roles to existing user
}
roles.clear(); // Clean up local memory

for(RoleEnum r : selectedRoles) { // User Input Roles
    UserRole role = new UserRole(entity, r); // New Entity with existing user
    Em.get().persist(role); // Role Entity Referenced to existing user object, saved
}

Em.get().merge(entity); // ?? No Need in edit unless roles are stored in user table
Em.get().flush();

Новый пользовательский режим:

List<UserRole> roles = entity.getRoles(); // New Detached User Entity Roles
    for(UserRole r : roles) { // Probably Empty Roles Array
        Em.get().remove(r); // Removed roles
    }
    roles.clear(); // Clean up Memory

    for(RoleEnum r : selectedRoles) { // Copy from App Roles
        UserRole role = new UserRole(entity, r); //Create new role
        Em.get().persist(role); //Save Role to DB
    }

    Em.get().merge(entity); // Trying to merge non existing Entity <-- This is where error appears
    Em.get().flush();

Метод persist работает, потому что он решает, когда использовать команду вставки или обновления. Поскольку для нового пользовательского объекта не задан идентификатор, он не знает, что с ним делать, хотя, возможно, он работал в прошлом, фактическое поведение mergig очень хорошо объяснено в этой теме объединение отдельного или нового объекта с существующая сущность в hibernate / jpa: вопрос передовой практики

Убедитесь сами:

Если ваша сущность является отдельной сущностью, единственное, что вам действительно нужно сделать, - это вызвать entityManager.merge (пользователь). Вам не нужно выполнять c любой метод поиска. Если ваша сущность не отделена, а скорее нова (для нее не указан идентификатор), вы должны найти соответствующую сущность в базе данных до выполнения каких-либо операций по изменению этой сущности и затем объединить ее.

Еще одна подробная ссылка здесь: persist () и merge () в JPA и Hibernate

Вот ссылка из документов:

Сериализуемый save (Object объект) выдает HibernateException

 Persist the given transient instance, first assigning a generated identifier. (Or using the current value of the identifier property if the assigned generator is used.) This operation cascades to associated instances if the association is mapped with cascade="save-update". 
 Parameters:
     object - a transient instance of a persistent class 
 Returns:
     the generated identifier 
 Throws:
     HibernateException

сохраняется

void persist (String entityName, Object object) выдает HibernateException

Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist".

The semantics of this method are defined by JSR-220.

Parameters:
    object - a transient instance to be made persistent 
Throws:
    HibernateException

объединить

Слияние объектов (String entityName, Object object) генерирует HibernateException

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".

The semantics of this method are defined by JSR-220.

Parameters:
    object - a detached instance with state to be copied 
Returns:
    an updated persistent instance 
Throws:
    HibernateException

save () и persist () в результате SQL INSERT, delete () в SQL DELETE и update () или merge () в SQL UPDATE. Изменения в постоянных случаях обнаруживаются во время гриппа sh и также приводят к SQL ОБНОВЛЕНИЮ. saveOrUpdate () и replicate () приводят либо к INSERT, либо к UPDATE.

Вывод: функции ведут себя так, как они предназначены.

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