Как использовать hibernate @DynamicUpdate с данными весны jpa? - PullRequest
0 голосов
/ 04 сентября 2018

Я использую Spring Data-JPA. Я хочу обновить только один столбец.

Мой репозиторий;

public interface UserRepository extends JpaRepository<User,Long> {
}

мой сервис;

public User save(User user) {
    return userRepository.save(user);
}

моя сущность;

@Entity
@DynamicUpdate(true)
public class User implements Serializable {
    // column definitions, etc.
}

Как мне обновить только один столбец в User?

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

Ваша проблема связана с передачей совершенно новой сущности User, поэтому Hibernate не может использовать кэшированную версию, которая уже была извлечена из базы данных, и решать, какие столбцы обновлять динамически.

Итак, попробуйте сделать следующее, чтобы подтвердить правильное поведение @DynamicUpdate;

В эксплуатации;

@Transactional
public User save(User newUser) {
    User currentUser = userRepository.get(newUser.getId());
    // handle merging of updated columns onto currentUser manually or via some mapping tool
    currentUser.setName(newUser.getName());
    return userRepository.save(currentUser);
}

Используя вышеуказанную логику вместе с динамической аннотацией обновления, вы сможете увидеть обновление столбца только с именем, если у вас не включен какой-либо аудит или используется столбец @Version 'ed.

Если обновленные столбцы всегда одинаковы, то лучше использовать updatable = false для столбцов, которые не являются целью обновления в их определениях @Column, поскольку использование @DynamicUpdate очень неэффективно, поскольку генерирует каждый sql заново, никогда не используя кэшированные sqls. Но будьте осторожны, используя эту функцию, поскольку вы вообще не сможете обновить эти столбцы.

Я не рекомендую использовать @Query, если у вас нет случая, когда собственный JPA / Hibernate недостаточен, но если у вас есть вариант использования для обновления только целевого набора столбцов, это лучший выбор, и наиболее эффективный.

Если обновленных столбцов много и они могут сильно различаться, либо определите логику сопоставления вручную между newUser и currentUser, либо используйте некоторые инструменты сопоставления, такие как Orika, у меня есть аналогичная автоматизированная структура, в которой сотни сущностей пропатчены через эти средства отображения, что позволяет чрезвычайно универсальным образом обрабатывать многие операции CRUD.

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

Прежде всего я хочу объяснить, почему @DynamicUpdate не работает для вас. Поэтому я должен заметить, как работает @DynamicUpdate:

Аннотация @DynamicUpdate используется для указания что оператор UPDATE SQL должен генерироваться всякий раз, когда объект модифицируется. По умолчанию Hibernate использует кэшированный оператор UPDATE, который устанавливает все столбцы таблицы. Когда сущность аннотируется с @DynamicUpdate аннотация, PreparedStatement собирается включить только столбцы, значения которых были изменены. ( подробнее )

Например, предположим, что User имеет свойство с именем name.

Таким образом, если вы впервые сохранили пользователя с определенным именем, теперь вы передаете null в качестве значения @DynamicUpdate, примет его как изменение и попытается обновить имя до null.

Первое решение:

В качестве первого решения, если вы хотите, чтобы @DynamicUpdate работал, сначала вы должны заполнить все остальные User свойства старыми значениями, затем вы можете сохранить его.

Плюсы: Сгенерированный запрос SQL просто обновляет желаемое свойство.

Минусы: Hibernate должен генерировать соответствующую строку SQL каждый раз, и, таким образом, на стороне Hibernate снижается производительность.

Второе решение:

Вы можете обновить User с помощью пользовательского запроса:

@Modifying
@Query("UPDATE User SET name=(:name) WHERE id=(:id)")
public void updateName(@Param("name")String name, @Param("id")Long id);

Третье решение:

В качестве последнего решения я могу предложить вам использовать updatable = false. Это заполнит свойство в самый первый момент, когда объект будет вставлен.

  @Column(name = "create_date", nullable = false, updatable = false)
    private Instant createDate;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...