Получить предыдущую версию entity in Hibernate Envers

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

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

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

5 ответов


может быть, это тогда (от AuditReader docs)

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));

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


вот еще одна версия, которая находит предыдущую ревизию относительно "текущего" номера редакции, поэтому ее можно использовать, даже если объект, на который вы смотрите, не является последней редакцией. Он также обрабатывает случай, когда там не предыдущая редакция. (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
}

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


документы:

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

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

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 );

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

  • вы должны передать свой EntityClass и Id вместо жесткого кодирования и принятия модели.
  • не "зашивать" в код своего экземпляра EntityManager.
  • нет смысла устанавливать selectDeleted, потому что удаленная запись никогда не может быть возвращена как предыдущая редакция.
  • вызов получить один результат с броском и исключением, если нет результатов или более 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];
}