10

我目前正在使用 Hibernate Envers。

如何删除与我要删除的实体相关的审计表中的条目?我的实体与其他实体没有关系。

我发现我必须在onPostDelete自定义侦听器的方法中这样做:

import org.hibernate.envers.event.AuditEventListener;
import org.hibernate.event.PostCollectionRecreateEvent;
import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PreCollectionRemoveEvent;
import org.hibernate.event.PreCollectionUpdateEvent;

public class MyListener extends AuditEventListener {

  ...
  @Override
  public void onPostDelete(PostDeleteEvent arg0) {
    // TODO Auto-generated method stub
    super.onPostDelete(arg0);
  }
  ...

}

我已经阅读了文档,论坛,很多东西,但我无法弄清楚。也许不可能,我不知道。

以前有人做过吗?

4

4 回答 4

4

好的,对于那些想知道的人,我已经完成了 50%。

感谢 Hibernate Envers 的创建者 Adam Warski,我引用:

“id”是实体id的休眠关键字,无论名称是什么;在审计实体的情况下,id 是复合的,称为“originalId”。尝试:

"delete from full.package.name.User_AUD u where u.originalId.id = :userid" 

但现在,我还想删除我的 revinfo 表中与审计表相关的条目。

如果有人有线索,请告诉我。

于 2010-05-11T18:46:24.497 回答
3

这对我来说完全有效,不需要本机查询

AuditQuery aq = auditReader.createQuery()
                   .forRevisionsOfEntity( ErpEmploye.class, true, false);       
 aq.add( AuditEntity.id().eq( employe.getCodeId() ) );
 aq.add( AuditEntity.relatedId("period").eq( erpPeriod.getCodeId() ) );
 List result =  aq.getResultList();//parameters must be added, this call is required
 if (result.size()>0){
    Query query = (Query) PrivateAccessor.invokePrivateMethod( aq, "buildQuery", new Object[0]);
    String queryString = (String) PrivateAccessor.getPrivateField( query, "queryString", true );
    PrivateAccessor.setPrivateField( query, "queryString", queryString.replace("select e__ from", "delete from"), true );
    getDAO().executeQuery(query);//transaction required             
}
于 2014-04-20T15:20:11.420 回答
2

如果您想通过 ID 清除修订,您可以使用本机查询直接访问 envers 表。有 2 个表包含对修订的引用。假设您的审计表使用传统的 _AUD 后缀,您可以通过编程方式找到实体表名称。

以下是一些用 Kotlin 编写的片段:

fun getAuditTableName(em: EntityManager, aClass: Class<*>): String {
    return getAuditTableName(em, aClass.name) + "_AUD"
}

fun getEntityTableName(em: EntityManager, aClass: Class<*>): String {
    val session = em.unwrap(Session::class.java) as Session
    val sessionFactory = session.sessionFactory
    val hibernateMetadata = sessionFactory.getClassMetadata(className)
    val persister = hibernateMetadata as AbstractEntityPersister
    return persister.tableName
}

现在我们有了表名,我们可以删除表中的行。(把它放在你的 JPA 事务块中,根据需要替换内容,并为你的提供者调整 SQL)。所以给定 MyEntityClass 和 myRevisionId,我们可以这样做:

    val em:EntityManager = getEntityManager()
    val auditTableName = getAuditTableName(MyEntityClass::class.java)

    em.createNativeQuery("delete from `$auditTableName` where REV=${myRevisionId}").executeUpdate()
    em.createNativeQuery("delete from REVINFO where REV=${myRevisionId}").executeUpdate()

如果要通过revisionID以外的参数删除,只需在entity_AUD表中查询revisionIds,然后按照上述方式删除找到的行。

请记住,一个 revisionId 可能与多个实体相关联,并且所有条目都将在前面的方法中删除。要删除单个实体的修订,您将需要实体的 ID 和实体的关键字段名称。

这是动态获取字段名称的代码:

fun getEntityKeyNames(em: EntityManager, entityClass: Class<*>): List<String> {
    val session = em.unwrap(Session::class.java) as Session
    val sessionFactory = session.sessionFactory
    val hibernateMetadata = sessionFactory.getClassMetadata(entityClass.name)
    val persister = hibernateMetadata as AbstractEntityPersister
    return persister.keyColumnNames.toList()
}
于 2017-11-01T02:05:36.423 回答
0

审计条目通常只添加,而不是删除,即使相关实体被删除,所以我不认为Envers API 对此提供支持。

现在,如果您真的想删除已删除实体的条目(这有点违背审计的目的),您可以稍微延迟一下,而不是在删除时删除条目,而是运行每日本地查询,例如每晚。

于 2010-05-08T13:39:06.723 回答