Заполнение таблиц редакций envers существующими данными из Hibernate Entities.

StackOverflow https://stackoverflow.com/questions/898529

Вопрос

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

Это было полезно?

Решение

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

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

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

Другие советы

Мы заполнили исходные данные, выполнив серию необработанных 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

Обратите внимание, что ИЗМЕНЕННЫЙ ТИП значение 0 для обозначения вставки (в отличие от модификации).

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

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

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

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

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

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;
  }
}

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top