2009-05-22 11 views
19

Estoy agregando enversiones a entidades de hibernación existentes. Todo está funcionando sin problemas en cuanto a la auditoría, sin embargo, la consulta es un problema diferente porque las tablas de revisión no están pobladas con los datos existentes. ¿Alguien más ya ha resuelto este problema? ¿Tal vez has encontrado alguna manera de completar las tablas de revisión con la tabla existente? Solo pensé en preguntar, estoy seguro de que otros lo encontrarían útil.Rellenar las tablas de revisión de enversiones con los datos existentes de las entidades de Hibernate

+0

¿Cómo le va la auditoría para trabajar? Ni siquiera puedo llegar tan lejos :( –

+1

Es muy simple, solo lea el manual bastante corto: http://www.jboss.org/files/envers/docs/index.html – danieljimenez

+0

Me preguntaba sobre esto, pero necesita información de auditoría sobre el medio ambiente.Qué usuario y "cómo" hicieron el cambio, qué operación de usuario de alto nivel estaban haciendo que desencadenó el cambio. Esto es importante para poder ver los cambios explícitos frente a los cambios de "efectos secundarios". ¿Sabes si envers maneja esta necesidad? – Pat

Respuesta

5

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

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

Este será construir una consulta que devuelve una lista de objetos [3]. El elemento Fisrt es su información, el segundo es la entidad de revisión y el tercero es el tipo de revisión.

+1

¿Podría ampliar esto más? ¿Estás diciendo que si la entidad de revisión es nula, entonces deberías simplemente usar el primer elemento de la matriz devuelta por AuditQuery? – Rezler

1

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 el funcionamiento de alto nivel . Usualmente esos son extraídos del contexto de ThreadLocal.

12

Hemos rellenado los datos iniciales ejecutando una serie de consultas SQL sin formato para simular "insertar" todas las entidades existentes como si acabaran de crearse 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 

Nota que el valor RevType es para indicar un inserto (en oposición a una modificación).

+0

Este enfoque me ha funcionado para resolver 'javax.persistence.EntityNotFoundException: no se ha podido encontrar con excepciones id x'. Específicamente, al cargar correctamente los datos secundarios de las auditorías históricas [SO: 5261139] (http://stackoverflow.com/questions/5261139/hibernate-envers-initializing-envers-proxies) se hicieron referencias a datos 'estáticos' (cargados fuera de Hibernate) llevando a esta excepción (Hibernate 4.2 actualmente). – user598656

2

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

ps: tenga en cuenta que este es un ejemplo simplificado. No funcionará de la caja, pero lo guiará hacia una solución de trabajo.

5

Tendrá un problema en esta categoría si está usando Envers ValidityAuditStrategy y tiene datos que han sido creados con la excepción de los Envers habilitados.

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

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

ValidityAuditStrategy with no audit record

Cuestiones relacionadas