如何从我的审计表中删除记录?

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

我已经完成了50%的工作,想知道的人可以看看。

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

"id"是一个Hibernate的关键字,表示实体的id,无论名称如何; 在审计实体的情况下,该id是组合的,并称为“originalId”。 请尝试:

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

但现在,我也想在我的revinfo表中删除与审计表相关的条目。如果有人有线索,请告诉我。

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             
}

我还需要从选择查询中删除 " order by. * ", 那么这对我也有效。Order by 可能是在 Envers 的较新版本中添加的。 - Dario Seidl

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

0

审计条目通常只会添加,即使相关实体被删除,也不会被删除,因此我认为Envers API不支持这一点。

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


感谢Pascal的时间。正如你所说,看起来Envers API不支持这个功能。在几个论坛上查看后,我找到了线索。我将不得不编写一个HQL查询: "delete from full.package.name.User_AUD u where u.id = :userid"它已经半奏效,因为现在我被一个Hibernate问题困住了... - Laurent T
你只需要使用一个私有访问器来将选择更改为删除,我刚刚发布了一个可行的解决方案,而不是使用本地SQL。 - Nassim MOUALEK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接