Get previous version of entity in Hibernate Envers

后端 未结 5 1743
孤街浪徒
孤街浪徒 2021-01-31 22:36

I have an entity loaded by Hibernate (via EntityManager):

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

This class is audited by Hibernate Enve

相关标签:
5条回答
  • 2021-01-31 23:22

    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 );
    
    0 讨论(0)
  • 2021-01-31 23:22

    From the docs:

    AuditReader reader = AuditReaderFactory.get(entityManager);
    User user_rev1 = reader.find(User.class, user.getId(), 1);
    
    0 讨论(0)
  • 2021-01-31 23:30

    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)

    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. Because I'm using the 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.

    0 讨论(0)
  • 2021-01-31 23:40

    Building off of the excellent approach of @brad-mace, I have made the following changes:

    • You should pass in your EntityClass and Id instead of hardcoding and assuming the Model.
    • Don't hardcode your EntityManager.
    • There is no point setting selectDeleted, because a deleted record can never be returned as the previous revision.
    • 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)
    • Get the revision, type, and entity in one transaction (remove the projection, use orderBy and maxResults, and query for the 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];
    }
    
    0 讨论(0)
  • 2021-01-31 23:42

    maybe this then (from 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));
    

    (I'm very new to this, not sure if I have all the syntax right, maybe the size()-1 should be size()-2?)

    0 讨论(0)
提交回复
热议问题