Hibernate 在修订之间休眠环境增量

Hibernate 在修订之间休眠环境增量,hibernate,spring-data-jpa,hibernate-envers,changeset,Hibernate,Spring Data Jpa,Hibernate Envers,Changeset,我需要为我的项目上的所有CRUD操作实现审计历史记录。该项目使用SpringJPA数据Rest。我环顾四周寻找好的库来完成所需的任务,并发现了这个库,它看起来非常好而且易于实现。将其纳入我的项目后,我能够记录所有CRUD操作的修订 现在我需要公开更改,用户可以在其中看到作为任何修订的一部分所做的更改。下面是我希望增量输出的方式(为了便于阅读,我将其设置为JSON格式) 我需要以JSON-HAL格式公开这些内容 提前感谢。有几种方法可以实现您的要求,但主要取决于您使用的Hibernate和Enve

我需要为我的项目上的所有CRUD操作实现审计历史记录。该项目使用SpringJPA数据Rest。我环顾四周寻找好的库来完成所需的任务,并发现了这个库,它看起来非常好而且易于实现。将其纳入我的项目后,我能够记录所有CRUD操作的修订

现在我需要公开更改,用户可以在其中看到作为任何修订的一部分所做的更改。下面是我希望增量输出的方式(为了便于阅读,我将其设置为JSON格式)

我需要以JSON-HAL格式公开这些内容


提前感谢。

有几种方法可以实现您的要求,但主要取决于您使用的Hibernate和Envers版本。如果您使用的是Hibernate 5.2及之前的版本,那么为了确定所需的信息,您的代码将需要进行一些额外的处理

我假设您拥有您感兴趣的实体的主键

List results = AuditReaderFactory.get( session ).createQuery()
  .forRevisionsOfEntity( YourEntityClass.class, false, true )
  .add( AuditEntity.id().eq( entityId ) )
  .addOrder( AuditEntity.revisionNumber().asc() )
  .getResultList();
此查询实际上返回一个
列表
,因为
forRevisionsOfEntity
的第二个参数为false。如果此参数的值为true,则返回值将为
List

由此可知,
列表中的每个条目都是基于以下配置的对象数组:

  • 索引0—该修订版的
    YourEntityClass
    实例
  • 索引1-修订实体的具体实现(稍后将对此进行详细介绍)
  • 索引2-
    RevisionType
    枚举值,可以是
    ADD
    MOD
    ,也可以是
    DEL
    。如果修改实体
的第三个参数为false,则永远不会有任何
DEL
类型 在这一点上,逻辑变得类似于:

YourEntityClass previousInstance = null;
for ( int i = 0; i < results.size(); ++i ) {
  Object[] row = (Object[]) results.get( i );
  if ( previousInstance == null ) {
    // this is the first revision, consider nothing changed here
    // so store a reference to it for the next row.
    previousInstance = row[0];
  }
  else {
    final YourRevisionEntity revEntity = (YourRevisionEntity) row[1];
    final String userName = revEntity.getUserName();
    final long revisionTimestamp = revEntity.getTimestamp();

    final YourEntityClass currentInstance = (YourEntityClass) row[0];
    List<Action> actions = resolveActions( previousInstance, currentInstance );
    // build your things

    previousInstance = currentInstance;
  }
}
此查询返回的数组类型与上面提到的5.2类型相同,只是在对象数组中包含一个附加对象:

  • 索引3-已更改属性的字符串集合
这种新方法的好主意是,不要像我在for
resolveActions
中提到的那样使用反射或某种类型的差异库,现在您已经知道具体更改了哪些属性,只需从对象实例中获取那些特定的值,这非常简单


最后一种方法仍在酝酿中,因此被认为是实验性的。我可能会看到索引3发生了变化,从而返回一个
元组
,其中可能包含属性/字段名和值,让用户可以更直接地使用它。

您能具体告诉我您使用的是哪个版本的Hibernate&Envers吗,因为这对哪些API最适合您所需的输出有一定的影响?您好@Naros,Hibernate和EnversHi@Naros的最终版本都是5.2.17。谢谢您的回复。我所做的正是您刚才描述的(根据5.2.17版)。我使用java对象差异库来比较这两个对象。你能告诉我一件事吗?我能把envers升级到最新版本,比如说5.4.1.Final,但保持hibernate到5.2.17,并获取已更改/添加/删除的属性集合吗?属性列表可能会包括所有属性,无论它们是否在修订之间添加/更新/删除。遗憾的是,您不能。由于
hibernate envers
hibernate core
都是串联构建的,因此关键是要使用相同的版本部署它们,以避免两个工件之间的兼容性问题。好的,谢谢。如果需要检索实体的特定修订的修订历史记录。我的代码在正确的下面吗?AuditQuery AuditQuery=AuditReaderFactory.get(entityManager).createQuery().forEntitiesAtRevision(entityClass,revisionId).add(AuditEntity.id().eq(financialGroupId))@SuppressWarnings(“未选中”)列表resultList=auditQuery.getResultList();if(resultList.size()!=1){抛出新的IllegalStateException(“未找到修订处的实体”);}返回resultList.get(0);}你好,纳罗斯,谢谢你。如果需要检索实体的特定修订的修订历史记录。我的代码在正确的下面吗<代码>AuditQuery AuditQuery=AuditReaderFactory.get(entityManager).createQuery().ForentiesAtRevision(entityClass,revisionId).add(AuditEntity.id().eq(financialGroupId))@SuppressWarnings(“未选中”)列表resultList=auditQuery.getResultList();if(resultList.size()!=1){抛出新的IllegalStateException(“未找到修订处的实体”);}返回resultList.get(0);}看起来不错,是的。请注意,如果该修订恰好是描述删除的修订,那么该方法将不返回任何结果,因为它被定义为仅返回插入和更新。
YourEntityClass previousInstance = null;
for ( int i = 0; i < results.size(); ++i ) {
  Object[] row = (Object[]) results.get( i );
  if ( previousInstance == null ) {
    // this is the first revision, consider nothing changed here
    // so store a reference to it for the next row.
    previousInstance = row[0];
  }
  else {
    final YourRevisionEntity revEntity = (YourRevisionEntity) row[1];
    final String userName = revEntity.getUserName();
    final long revisionTimestamp = revEntity.getTimestamp();

    final YourEntityClass currentInstance = (YourEntityClass) row[0];
    List<Action> actions = resolveActions( previousInstance, currentInstance );
    // build your things

    previousInstance = currentInstance;
  }
}
List results = AuditReaderFactory.get( session ).createQuery()
  .forRevisionsOfEntityWithChanges( YourEntityClass.class, false, true )
  .add( AuditEntity.id().eq( entityId ) )
  .addOrder( AuditEntity.revisionNumber().asc() )
  .getResultList();