Заполните таблицы ревизий с существующими данными из Hibernate Entities - PullRequest
19 голосов
/ 22 мая 2009

Я добавляю envers к существующим спящим объектам. Все работает гладко, что касается аудита, однако запросы - это другая проблема, поскольку таблицы ревизий не заполнены существующими данными. Кто-нибудь еще уже решил эту проблему? Может быть, вы нашли способ заполнить таблицы ревизий существующей таблицей? Просто подумал, что я спрошу, я уверен, что другие найдут это полезным.

Ответы [ 5 ]

13 голосов
/ 02 декабря 2011

Мы заполнили исходные данные, выполнив ряд необработанных SQL-запросов, чтобы имитировать «вставку» всех существующих объектов, как если бы они были созданы одновременно. Например:

insert into REVINFO(REV,REVTSTMP) values (1,1322687394907); 
-- this is the initial revision, with an arbitrary timestamp

insert into item_AUD(REV,REVTYPE,id,col1,col1) select 1,0,id,col1,col2 from item; 
-- this copies the relevant row data from the entity table to the audit table

Обратите внимание, что значение REVTYPE равно 0 для обозначения вставки (в отличие от модификации).

6 голосов
/ 17 января 2014

У вас возникнут проблемы в этой категории, если вы используете Envers ValidityAuditStrategy и у вас есть данные, которые были созданы не с включенным Envers.

В нашем случае (Hibernate 4.2.8.Final) базовое обновление объекта выдает «Невозможно обновить предыдущую версию для объекта и» (зарегистрировано как [org.hibernate.AssertionFailure] HHH000099).

Мне потребовалось некоторое время, чтобы найти это обсуждение / объяснение, поэтому перекрестная публикация:

ValidityAuditStrategy без записи аудита

5 голосов
/ 02 июня 2011

Вам не нужно.
AuditQuery позволяет вам получить RevisionEntity и ревизию данных:

AuditQuery query = getAuditReader().createQuery()
                .forRevisionsOfEntity(YourAuditedEntity.class, false, false);

Это создаст запрос, который возвращает список объектов [3]. Элемент Fisrt - это ваши данные, второй - объект редакции, а третий - тип редакции.

2 голосов
/ 23 августа 2012

Мы решили проблему заполнения журналов аудита существующими данными следующим образом:

SessionFactory defaultSessionFactory;

// special configured sessionfactory with envers audit listener + an interceptor 
// which flags all properties as dirty, even if they are not.
SessionFactory replicationSessionFactory;

// Entities must be retrieved with a different session factory, otherwise the 
// auditing tables are not updated. ( this might be because I did something 
// wrong, I don't know, but I know it works if you do it as described above. Feel
// free to improve )

FooDao fooDao = new FooDao();
fooDao.setSessionFactory( defaultSessionFactory );
List<Foo> all = fooDao.findAll();

// cleanup and close connection for fooDao here.
..

// Obtain a session from the replicationSessionFactory here eg.
Session session = replicationSessionFactory.getCurrentSession();

// replicate all data, overwrite data if en entry for that id already exists
// the trick is to let both session factories point to the SAME database.
// By updating the data in the existing db, the audit listener gets triggered,
// and inserts your "initial" data in the audit tables.
for( Foo foo: all ) {
    session.replicate( foo, ReplicationMode.OVERWRITE ); 
}     

Конфигурация моих источников данных (через Spring):

<bean id="replicationDataSource" 
      class="org.apache.commons.dbcp.BasicDataSource" 
      destroy-method="close">
  <property name="driverClassName" value="org.postgresql.Driver"/>
  <property name="url" value=".."/>
  <property name="username" value=".."/>
  <property name="password" value=".."/>
  <aop:scoped-proxy proxy-target-class="true"/>
</bean>

<bean id="auditEventListener" 
      class="org.hibernate.envers.event.AuditEventListener"/>

<bean id="replicationSessionFactory"
      class="o.s.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

  <property name="entityInterceptor">
    <bean class="com.foo.DirtyCheckByPassInterceptor"/>
  </property>

  <property name="dataSource" ref="replicationDataSource"/>
  <property name="packagesToScan">
    <list>
      <value>com.foo.**</value>
    </list>
  </property>

  <property name="hibernateProperties">
    <props>
      ..
      <prop key="org.hibernate.envers.audit_table_prefix">AUDIT_</prop>
      <prop key="org.hibernate.envers.audit_table_suffix"></prop>
    </props>
  </property>
  <property name="eventListeners">
    <map>
      <entry key="post-insert" value-ref="auditEventListener"/>
      <entry key="post-update" value-ref="auditEventListener"/>
      <entry key="post-delete" value-ref="auditEventListener"/>
      <entry key="pre-collection-update" value-ref="auditEventListener"/>
      <entry key="pre-collection-remove" value-ref="auditEventListener"/>
      <entry key="post-collection-recreate" value-ref="auditEventListener"/>
    </map>
  </property>
</bean>

Перехватчик:

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
..

public class DirtyCheckByPassInterceptor extends EmptyInterceptor {

  public DirtyCheckByPassInterceptor() {
    super();
  }


  /**
   * Flags ALL properties as dirty, even if nothing has changed. 
   */
  @Override
  public int[] findDirty( Object entity,
                      Serializable id,
                      Object[] currentState,
                      Object[] previousState,
                      String[] propertyNames,
                      Type[] types ) {
    int[] result = new int[ propertyNames.length ];
    for ( int i = 0; i < propertyNames.length; i++ ) {
      result[ i ] = i;
    }
    return result;
  }
}

ps: имейте в виду, что это упрощенный пример. Он не будет работать сразу после установки, но поможет вам найти рабочее решение.

1 голос
/ 15 июля 2009

Взгляните на http://www.jboss.org/files/envers/docs/index.html#revisionlog

По сути, вы можете определить свой собственный «тип редакции», используя аннотацию @RevisionEntity, а затем реализовать интерфейс RevisionListener для вставки дополнительных данных аудита, как текущий пользователь и операция высокого уровня. Обычно они извлекаются из контекста ThreadLocal.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...