Pregunta

Estoy agregando envers a una hibernación entidades existentes. Todo está funcionando sin problemas hasta el momento en cuanto a la auditoría, sin embargo, la consulta es un asunto diferente, porque las tablas de revisión no se rellenan con los datos existentes. Alguien más ya resuelto este problema? Tal vez has encontrado alguna manera de llenar las tablas de revisión con la tabla existente? Sólo pensé en preguntar, estoy seguro que otros lo encuentren útil.

¿Fue útil?

Solución

No es necesario.
AuditQuery le permite obtener tanto RevisionEntity y revisión de datos por:

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

Esto construir una consulta que devuelve una lista de Object [3]. fisrt elemento es sus datos, el segundo es la entidad de revisión y el tercero es el tipo de revisión.

Otros consejos

poblamos los datos iniciales mediante la ejecución de una serie de consultas SQL primas para simular "la inserción de" todas las entidades existentes como si hubieran sido creados al mismo tiempo. Por ejemplo:

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

Tenga en cuenta que la valor RevType es 0 para indicar un inserto (en oposición a una modificación).

Vas a tener un problema en esta categoría si está utilizando Envers ValidityAuditStrategy y tienen datos que han sido creados sí que con Envers habilitadas.

En nuestro caso (Hibernate 4.2.8.Final) una actualización del objeto básico tiros "No se puede actualizar la revisión anterior de entidad y" (registrada como [org.hibernate.AssertionFailure] HHH000099).

Me tomó un tiempo para encontrar esta discusión / explicación por lo que la publicación cruzada:

ValidityAuditStrategy sin registro de auditoría

Hemos resuelto el problema de poblar los registros de auditoría con los datos existentes de la siguiente manera:

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

La configuración de mis fuentes de datos (a través de 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>

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

PD: ten en cuenta que este es un ejemplo simplificado. No va a funcionar fuera de la caja, sino que le guiará hacia una solución de trabajo.

Tome un vistazo a http://www.jboss.org /files/envers/docs/index.html#revisionlog

Básicamente se puede definir su propio 'tipo de revisión' mediante anotación @RevisionEntity, y luego implementar una interfaz RevisionListener que introducir sus datos de auditoría adicionales, como usuario actual y operación de alto nivel. Por lo general, los sacaron de contexto ThreadLocal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top