4

I'm using Hibernate Envers in my app to track changes in all fields of my entities. I'm using @Audited(withModifiedFlag=true) annotation to do it.

The records are been correcty recorded at database and the _mod fields correctly indicate the changed fields.

I want to get a particular revision from some entity and the information of what fields have been changed. I'm using the follow method to do it:

        List<Object[]> results = reader.createQuery()  
            .forRevisionsOfEntity(this.getDao().getClazz(), false, true)  
            .add(AuditEntity.id().eq(id))  
            .getResultList(); 

This method returns an list of an object array with my entity as first element.

The problem is that the returned entity doesn't have any information about the changed fields. So, my question is: how to get the information about the changed fields?

  • You could try this: http://stackoverflow.com/questions/17577363/getting-the-old-value-and-new-value-between-two-revisions-with-hibernate-envers with this http://stackoverflow.com/questions/793674/get-previous-version-of-entity-in-hibernate-envers – dgofactory Jul 02 '15 at 15:31
  • These guys want exactly the same thing than I. Looks like envers do not give it by default. I will try to implement that solution, recovering the previous object and setting by myself the diff. Thank you! – Fabio Barbosa Jul 02 '15 at 18:05

1 Answers1

3

I know that this question is a bit old now but I was trying to do this and didn't really find any answers.

There doesn't seem to be a nice way to achieve this, but here is how I went about it.

Firstly you need to use projections, which no longer gives you a nice entity model already mapped for you. You'll still get back an array of Objects but each object in the array corresponds to each projection that you added (in order).

final List<Object[]> resultList = reader.createQuery()  
        .forRevisionsOfEntity(this.getDao().getClazz(), false, true)
        // if you want revision properties like revision number/type etc
        .addProjection(AuditEntity.revisionNumber())
        // for your normal entity properties
        .addProjection(AuditEntity.id())
        .addProjection(AuditEntity.property("title")) // for each of your entity's properties
        // for the modification properties
        .addProjection(new AuditProperty<Object>(new ModifiedFlagPropertyName(new EntityPropertyName("title"))))
        .add(AuditEntity.id().eq(id))
        .getResultList();

You then need to map each result manually. This part is up to you, but I'm use a separate class as a revision model as it contains extra data to the normal entity data. If you wanted you could probably achieve this with @Transient properties on your entity class though.

final List<MyEntityRevision> results = resultList.stream().map(this::transformRevisionResult)
            .collect(Collectors.toList());


private MyEntityRevision transformRevisionResult(Object[] revisionObjects) {
    final MyEntityRevision rev = new MyEntityRevision();
    rev.setRevisionNumber((Integer) revisionObjects[0]);
    rev.setId((Long) revisionObjects[1]);
    rev.setTitle((String) revisionObjects[2]);
    rev.setTitleModified((Boolean) revisionObjects[3]);
    return rev;
}
Nathan
  • 51
  • 3