У меня есть объект, загруженный Hibernate (через EntityManager
):
User u = em.load(User.class, id)
Этот класс проверяется с помощью Hibernate Envers. Как загрузить предыдущую версию объекта User?
У меня есть объект, загруженный Hibernate (через EntityManager
):
User u = em.load(User.class, id)
Этот класс проверяется с помощью Hibernate Envers. Как загрузить предыдущую версию объекта User?
возможно, это тогда (из 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));
(Я очень новичок в этом, не уверен, что у меня есть весь синтаксис, возможно, size() - 1 должен быть size() - 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
}
Единственный сложный бит с этим обобщением - это получение идентификатора объекта. Потому что я использую Play! framework, я могу использовать тот факт, что все сущности являются Моделями и используют ((Model) entity).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, я внес следующие изменения:
Итак, другое решение:
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];
}