Hibernate Envers : How to check if a field has changed between two revisions?

本小妞迷上赌 提交于 2019-12-24 16:08:41

问题


I am using Hibernate envers to audit entities in my application. I have separate _audit tables for each entity and then in those tables I have _mod boolean column to indicate if the field has changed or not.

But, I m not getting how to use that column in queries or even how do I get this data in the code?

e.g. following code gives list of audited persons. How do I check which data has changed?

List person = getAuditReader().createQuery()
    .forEntitiesAtRevision(Person.class, 12)
    .getResultList();

回答1:


You can loop through all the fields of the given entity and find out if that field is changed or not.

Sample code snippet to loop through all the fields of Person entity for revision number 12 and find value of fields which are updated.

  public void processFields() throws Exception {
    for (Field field : Person.class.getDeclaredFields()) {
      final Person changedEntity = fetchEntityForRevisionWhenPropertyChanged(Person.class, 12, field.getName());
      if (changedEntity != null) {
        // Updated field value for the field. This will list all fields which are changed in given revision.
        final Object fieldValue = getField(changedEntity, field.getName());
      }
    }
  }

  private  <T> Object getField(final T object, final String fieldName) throws Exception {
    return new PropertyDescriptor(fieldName, object.getClass()).getReadMethod().invoke(object);
  }

  private  <T> T fetchEntityForRevisionWhenPropertyChanged(final Class<T> entityClass, final int revisionNumber, final String propertyName) {
    final List<T> resultList = getAuditReader()
        .createQuery()
        .forEntitiesModifiedAtRevision(entityClass, revisionNumber)
        .add(AuditEntity.property(propertyName).hasChanged())
        .addOrder(AuditEntity.id().asc())
        .getResultList();

    if (CollectionUtils.isNotEmpty(resultList)) {
      return resultList.get(0);
    } else {
      return null;
    }
  }

In any case if you want to find previous revison of your entity for comparision, you can use following method:

  public T getPreviousVersion(final Class<T> entityClass, final Long entityId, final Long currentRevisionNumber) {
    final AuditReader reader = AuditReaderFactory.get(entityManager);

    final Number previousRevision = (Number) reader.createQuery()
        .forRevisionsOfEntity(entityClass, false, true)
        .addProjection(AuditEntity.revisionNumber().max())
        .add(AuditEntity.id().eq(entityId))
        .add(AuditEntity.revisionNumber().lt(currentRevisionNumber))
        .getSingleResult();

    return Optional.ofNullable(previousRevision)
        .map(previousRev -> reader.find(entityClass, entityId, previousRev))
        .orElse(null);
  }



回答2:


You can try to use Hibernate interceptors. Here is good article about interceptors. With interceptor you can create a callback which would be executed on entity updates/creation etc. It would be smth like this:

public class EntityInterceptor extends EmptyInterceptor {
    @Override
    public boolean onFlushDirty(Object entity,
                                Serializable id,
                                Object[] currentState,
                                Object[] previousState,
                                String[] propertyNames,
                                Type[] types) {
        if ( entity instanceof YourEntity ) {
            //do update stuff
            return true;
        }
        return false;
    }
}

You can compare currentState with previousState to collect information about entity changes and persist it to other tables.



来源:https://stackoverflow.com/questions/36277333/hibernate-envers-how-to-check-if-a-field-has-changed-between-two-revisions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!