Как удалить записи из моей таблицы аудита?

В настоящее время я работаю с 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);
  }
  ...

}

Я читал документацию, форумы, много всего, но не могу понять. Может быть, это невозможно, я не знаю.

Кто-нибудь когда-нибудь делал это раньше?


person Laurent T    schedule 07.05.2010    source источник


Ответы (4)


Хорошо, я на 50% закончил с этим для тех, кто хочет знать.

Спасибо создателю Hibernate Envers Адаму Варски, цитирую:

«id» — это ключевое слово hibernate для идентификатора сущности, какими бы ни были имена; в случае объектов аудита идентификатор является составным и называется «originalId». Пытаться:

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

Но теперь я также хотел бы удалить записи, связанные с таблицей аудита, в моей таблице revinfo.

Если у кого-то есть ключ, дайте мне знать.

person Laurent T    schedule 11.05.2010

Это полностью работает для меня, и нативный запрос не требуется

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             
}
person Nassim MOUALEK    schedule 20.04.2014
comment
Мне также пришлось удалить " order by.*" из запроса выбора, тогда это тоже работает для меня. Заказ по, вероятно, был добавлен в более поздней версии Envers. - person Dario Seidl; 16.02.2021

Если вы хотите стереть ревизию по идентификатору, вы можете получить доступ к таблице 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()

Если вы хотите удалить по параметру, отличному от идентификатора ревизии, просто запросите идентификаторы ревизий в таблице entity_AUD, а затем удалите найденные строки указанным способом.

Имейте в виду, что ревизия может быть связана более чем с 1 сущностью, и все записи будут удалены в предыдущем методе. Чтобы удалить ревизию для одного объекта, вам потребуется идентификатор объекта и имена ключевых полей объекта.

Вот код для динамического получения имени поля:

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()
}
person Steven Spungin    schedule 01.11.2017

Записи аудита обычно только добавляются, а не удаляются, даже когда связанный объект удаляется, поэтому я не думаю, что Envers API поддерживает это.

Теперь, если вы действительно хотите удалить записи для удаленных объектов (это противоречит цели аудита), вы можете немного отложить это и вместо удаления записей во время удаления запускать ежедневный собственный запрос, например, каждую ночь.

person Pascal Thivent    schedule 08.05.2010
comment
Спасибо, Паскаль, за ваше время. Как вы сказали, похоже, что Envers API не поддерживает это. Просмотрев несколько форумов, я нашел подсказку. Мне придется написать HQL-запрос: удалить из full.package.name.User_AUD u, где u.id = :userid Это работает наполовину, потому что теперь я застрял с проблемой Hibernate... - person Laurent T; 10.05.2010
comment
Вам просто нужно использовать Private Accessor, чтобы изменить выбор для удаления, я просто публикую рабочее решение без собственного SQL. - person Nassim MOUALEK; 20.04.2014