Hibernate Envers:如何检查两个修订版之间的字段是否已更改?

时间:2016-03-29 06:50:33

标签: java spring hibernate-envers

我正在使用Hibernate envers来审核我的应用程序中的实体。我为每个实体都有单独的_audit表,然后在那些表中我有_mod布尔列来指示字段是否已更改。

但是,我没有得到如何在查询中使用该列,甚至如何在代码中获取此数据?

e.g。以下代码给出了被审计人员的清单。如何检查哪些数据已更改?

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

2 个答案:

答案 0 :(得分:0)

您可以遍历给定实体的所有字段,并找出该字段是否更改。

示例代码段可循环遍历Person实体的所有修订版本号为12的字段,并查找已更新字段的值。

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

在任何情况下,如果要查找您的实体的先前版本以进行比较,则可以使用以下方法:

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

答案 1 :(得分:-1)

您可以尝试使用Hibernate拦截器。关于拦截器的Here is好文章。 使用拦截器,您可以创建一个回调,它将在实体更新/创建等时执行。它会像这样:

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

您可以将 currentState previousState 进行比较,以收集有关实体更改的信息,并将其保存到其他表中。