简体   繁体   English

在Hibernate Envers中获取以前版本的实体

[英]Get previous version of entity in Hibernate Envers

I have an entity loaded by Hibernate (via EntityManager ): 我有一个由Hibernate加载的实体(通过EntityManager ):

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

This class is audited by Hibernate Envers. 该课程由Hibernate Envers审核。 How can I load the previous version of a User entity? 如何加载以前版本的用户实体?

Here's another version that finds the previous revision relative to a "current" revision number, so it can be used even if the entity you're looking at isn't the latest revision. 这是另一个版本,它找到相对于“当前”版本号的先前版本,因此即使您正在查看的实体不是最新版本,也可以使用它。 It also handles the case where there isn't a prior revision. 它还处理没有事先修订的情况。 ( em is assumed to be a previously-populated EntityManager) (假设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
}

This can be generalized to: 这可以推广到:

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
}

The only tricky bit with this generalization is getting the entity's id. 这种泛化的唯一棘手的一点是获得实体的id。 Because I'm using the Play! 因为我正在使用Play! framework, I can exploit the fact that all entities are Models and use ((Model) entity).id to get the id, but you'll have to adjust this to suit your environment. 框架,我可以利用所有实体都是模型并使用((Model) entity).id获取id的事实,但你必须调整它以适应你的环境。

maybe this then (from AuditReader docs) 也许这就是(来自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));

(I'm very new to this, not sure if I have all the syntax right, maybe the size()-1 should be size()-2?) (我对此非常新,不确定我是否拥有正确的语法,也许大小() - 1应该是size() - 2?)

I think it would be this: 我想是这样的:

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

Building off of the excellent approach of @brad-mace, I have made the following changes: 基于@ brad-mace的出色方法,我做了以下更改:

  • You should pass in your EntityClass and Id instead of hardcoding and assuming the Model. 你应该传入你的EntityClass和Id而不是硬编码并假设模型。
  • Don't hardcode your EntityManager. 不要硬编码您的EntityManager。
  • There is no point setting selectDeleted, because a deleted record can never be returned as the previous revision. 没有设置selectDeleted的点,因为删除的记录永远不能作为前一版本返回。
  • Calling get single result with throw and exception if no results or more than 1 result is found, so either call resultlist or catch the exception (this solution calls getResultList with maxResults = 1) 如果没有找到结果或超过1个结果,则调用使用throw和exception获取单个结果,因此调用resultlist或捕获异常(此解决方案调用getResultList with maxResults = 1)
  • Get the revision, type, and entity in one transaction (remove the projection, use orderBy and maxResults, and query for the Object[3] ) 在一个事务中获取修订,类型和实体(删除投影,使用orderBy和maxResults,并查询Object [3])

So here's another solution: 所以这是另一个解决方案:

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];
}

From the docs: 来自文档:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM