Pergunta

Eu estou adicionando envers a um entidades de hibernação existentes. Tudo está funcionando bem até agora, tanto quanto a auditoria, no entanto a consulta é uma questão diferente, porque as tabelas de revisão não são preenchidos com os dados existentes. Tem mais alguém já resolveu esta questão? Talvez você tenha encontrado alguma forma para preencher as tabelas de revisão com a tabela existente? Apenas pensei em perguntar, eu tenho certeza que outros iria encontrá-lo útil.

Foi útil?

Solução

Você não precisa.
AuditQuery permite obter tanto RevisionEntity e revisão de dados por:

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

Isto irá construir uma consulta que retorna uma lista de Object [3]. elemento Fisrt é os seus dados, o segundo é a entidade revisão e o terceiro é o tipo de revisão.

Outras dicas

Nós povoada os dados iniciais, executando uma série de consultas SQL matérias para simular "Inserir" todas as entidades existentes, como se tivessem acabado de ser criado ao mesmo tempo. Por exemplo:

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

Note-se que o REVTYPE valor é 0 para indicar uma inserção (em oposição a uma modificação).

Você vai ter um problema nesta categoria se você estiver usando Envers ValidityAuditStrategy e ter dados que foram criados outros do que com Envers habilitado.

No nosso caso (Hibernate 4.2.8.Final) uma atualização de objeto básico lança "Não é possível atualizar revisão anterior para a entidade e" (registrado como [org.hibernate.AssertionFailure] HHH000099).

Levei um tempo para encontrar essa discussão / explicação tão cross-posting:

ValidityAuditStrategy sem registro de auditoria

Nós resolvemos a questão de povoar os logs de auditoria com os dados existentes como se segue:

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

A configuração das minhas fontes de dados (via Primavera):

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

O interceptor:

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: manter em mente que este é um exemplo simplificado. Não vai funcionar fora da caixa, mas ele irá guiá-lo em direção a uma solução de trabalho.

Dê uma olhada http://www.jboss.org /files/envers/docs/index.html#revisionlog

Basicamente, você pode definir o seu próprio 'Tipo de revisão' usando anotação @RevisionEntity, e, em seguida, implementar uma interface RevisionListener para inserir seus dados de auditoria adicionais, como usuário atual e operação de alto nível. Normalmente, esses são retirados do contexto ThreadLocal.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top