сенсорный эквивалент для спящего объекта - PullRequest
0 голосов
/ 14 октября 2019

Я хотел бы реализовать метод репозитория void touch(MyEntity myEntity), который обеспечивает вызов SQL обновления столбцов сущностей до их текущих значений. (Причина заключается в триггере on update, который необходимо вызывать в какой-то момент выполнения.) Идеальный вариант использования:

void serviceMethod(Long myEntityId) {
    MyEntity myEntity = myEntityRepository.findOne(myEntityId);
    ...
    myEntityRepository.touch(myEntity);
    ...
}

Уже есть похожие вопросы по SO, которые у меня не работают: Принудительное обновление в Hibernate (моя сущность отсоединена), Реализация «прикосновения» к сущности JPA? (выполнение каких-то безобидных изменений работает, но не является общим и плохо влияет на читаемость кода), Обновление Hibernate Idempotent (аналогичный пример).

Мне известен метод перехвата сеанса findDirty, а также CustomEntityDirtinessStrategy, оба описаны в этой статьи Влада Михалчеа . Тем не менее, он, похоже, использует findDirty Я должен был бы переопределить перехватчик сеанса, что невозможно изнутри метода репозитория, так как перехватчик является конечным полем, назначенным сеансу при создании сеанса. И CustomEntityDirtinessStrategy происходит от SessionFactory, который является глобальным. Мне скорее нужно какое-то одноразовое решение, чтобы временно считать одну конкретную сущность одного конкретного класса грязной.

На сегодняшний день наилучшим рабочим решением является установка недопустимого (массива нулей) снимка сущности в контекст постоянства, поэтомучто последующая логика в flush() оценивает сущность как отличающуюся от снимка и обеспечивает обновление. Это работает:

@Override
@Transactional
public void touch(final T entity) {
    SessionImpl session = (SessionImpl)em.getDelegate();
    session.update(entity);
    StatefulPersistenceContext pctx = (StatefulPersistenceContext) session.getPersistenceContext();
    Serializable id = session.getIdentifier(entity);
    EntityPersister persister = session.getEntityPersister(null, entity);
    EntityKey entityKey = session.generateEntityKey(id, persister);
    int length = persister.getPropertyNames().length;
    Field entitySnapshotsByKeyField = FieldUtils.getField(pctx.getClass(), "entitySnapshotsByKey", true);
    Map<EntityKey,Object> entitySnapshotsByKey = (Map<EntityKey,Object>)ReflectionUtils.getField(entitySnapshotsByKeyField, pctx);
    entitySnapshotsByKey.put(entityKey, new Object[length]);
    session.flush();
    em.refresh(entity);
}

Совет в Принудительное обновление в Hibernate у меня не сработало, потому что session.evict(entity) очищает entitySnapshotsByKey запись вообще, что вызывает последующие org.hibernate.event.internal.DefaultFlushEntityEventListener#getDatabaseSnapshot загрузкисвежая сущность из БД. Вопросу 9 лет, и я не уверен, применим ли он к текущей версии Hibernate (у меня 5.2.17).

Хотя я не удовлетворен таким хакерским решением. Есть ли какой-то простой способ или что-то, что я мог бы сделать проще?

...