Получить предыдущую версию сущности в Hibernate Envers - PullRequest
10 голосов
/ 27 апреля 2009

У меня есть объект, загруженный Hibernate (через EntityManager):

User u = em.load(User.class, id)

Этот класс проверен Hibernate Envers. Как я могу загрузить предыдущую версию объекта User?

Ответы [ 5 ]

23 голосов
/ 11 августа 2011

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

public static User getPreviousVersion(User user, int current_rev) {
    AuditReader reader = AuditReaderFactory.get(em);

    Number prior_revision = (Number) reader.createQuery()
    .forRevisionsOfEntity(User.class, false, true)
    .addProjection(AuditEntity.revisionNumber().max())
    .add(AuditEntity.id().eq(user.getId()))
    .add(AuditEntity.revisionNumber().lt(current_rev))
    .getSingleResult();

    if (prior_revision != null)
        return (User) reader.find(User.class, user.getId(), prior_revision);
    else
        return null
}

Это можно обобщить до:

public static T getPreviousVersion(T entity, int current_rev) {
    AuditReader reader = AuditReaderFactory.get(JPA.em());

    Number prior_revision = (Number) reader.createQuery()
    .forRevisionsOfEntity(entity.getClass(), false, true)
    .addProjection(AuditEntity.revisionNumber().max())
    .add(AuditEntity.id().eq(((Model) entity).id))
    .add(AuditEntity.revisionNumber().lt(current_rev))
    .getSingleResult();

    if (prior_revision != null)
        return (T) reader.find(entity.getClass(), ((Model) entity).id, prior_revision);
    else
        return null
}

Единственный сложный момент с этим обобщением - получение идентификатора сущности. Потому что я использую Play! Framework, я могу использовать тот факт, что все сущности являются моделями и использовать ((Model) entity).id для получения идентификатора, но вам придется изменить это в соответствии с вашей средой.

10 голосов
/ 19 мая 2009

может быть тогда (из AuditReader документы)

AuditReader reader = AuditReaderFactory.get(entityManager);
User user_rev1 = reader.find(User.class, user.getId(), 1);

List<Number> revNumbers = reader.getRevisions(User.class, user_rev1);
User user_previous = reader.find(User.class, user_rev1.getId(),
  revNumbers.get(revNumbers.size()-1));

(я очень новичок в этом, не уверен, что у меня весь синтаксис правильный, возможно, size () - 1 должен быть size () - 2?)

1 голос
/ 01 ноября 2017

Основываясь на превосходном подходе @ brad-mace, я внес следующие изменения:

  • Вы должны передать свой EntityClass и Id вместо жесткого кодирования и принятия модели.
  • Не кодируйте ваш EntityManager.
  • Нет настройки точки selectDeleted, поскольку удаленная запись никогда не может быть возвращена в качестве предыдущей ревизии.
  • Вызов get для одного результата с броском и исключением, если не найдено ни одного результата или более 1 результата, поэтому вызовите resultlist или перехватите исключение (это решение вызывает getResultList с maxResults = 1)
  • Получить ревизию, тип и сущность в одной транзакции (удалить проекцию, использовать orderBy и maxResults и запросить объект [3])

Так вот еще одно решение:

public static <T> T getPreviousRevision(EntityManager entityManager, Class<T> entityClass, Object entityId, int currentRev) {
    AuditReader reader = AuditReaderFactory.get(entityManager);
    List<Object[]> priorRevisions = (List<Object[]>) reader.createQuery()
            .forRevisionsOfEntity(entityClass, false, false)
            .add(AuditEntity.id().eq(entityId))
            .add(AuditEntity.revisionNumber().lt(currentRev))
            .addOrder(AuditEntity.revisionNumber().desc())
            .setMaxResults(1)
            .getResultList();

    if (priorRevisions.size() == 0) {
        return null;
    }
    // The list contains a single Object[] with entity, revinfo, and type 
    return (T) priorRevision.get(0)[0];
}
1 голос
/ 20 мая 2009

Я думаю, это будет так:

final AuditReader reader = AuditReaderFactory.get( entityManagerOrSession );

// This could probably be declared as Long instead of Object
final Object pk = userCurrent.getId();

final List<Number> userRevisions = reader.getRevisions( User.class, pk );

final int revisionCount = userRevision.size();

final Number previousRevision = userRevisions.get( revisionCount - 2 );

final User userPrevious = reader.find( User.class, pk, previousRevision );
1 голос
/ 27 апреля 2009

Из документов:

AuditReader reader = AuditReaderFactory.get(entityManager);
User user_rev1 = reader.find(User.class, user.getId(), 1);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...