Domanda

Sto aggiungendo envers a un'entità Hibernate esistenti. Tutto funziona senza problemi per quanto riguarda la revisione, tuttavia interrogazione è una questione diversa, perché le tabelle di revisione non sono occupati con i dati esistenti. Qualcun altro ha già risolto questo problema? Forse hai trovato un modo per popolare le tabelle di revisione con la tabella esistente? Ho pensato di chiedere, sono sicuro che gli altri lo troverebbero utile.

È stato utile?

Soluzione

Non è necessario.
AuditQuery consente di ottenere sia RevisionEntity e la revisione dei dati da:

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

In questo modo creare una query che restituisce un elenco di Object [3]. Elemento fisrt è i dati, il secondo è l'entità di revisione e il terzo è il tipo di revisione.

Altri suggerimenti

Abbiamo popolato i dati iniziali eseguendo una serie di query SQL prime per simulare "inserendo" tutte le entità esistenti come se fossero stati appena creato allo stesso tempo. Ad esempio:

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

Si noti che il RevType valore 0 per indicare un inserto (in contrapposizione ad una modifica).

Avrete un problema in questa categoria se si utilizza Envers ValidityAuditStrategy e hanno dati che sono stati creati diversi da quelli con Envers abilitati.

Nel nostro caso (Hibernate 4.2.8.Final) un aggiornamento di oggetto base getta "Impossibile aggiornare revisione precedente per l'entità e" (registrata come [org.hibernate.AssertionFailure] HHH000099).

Mi ci volle un po 'per trovare questa discussione / spiegazione in modo cross-posting:

ValidityAuditStrategy senza record di controllo

Abbiamo risolto il problema di popolare i registri di controllo con i dati esistenti nel seguente modo:

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 configurazione delle mie fonti di dati (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>

L'intercettore:

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: tenere a mente che questo è un esempio semplificato. Non funzionerà fuori dalla scatola, ma vi guiderà verso una soluzione di lavoro.

Date un'occhiata a http://www.jboss.org /files/envers/docs/index.html#revisionlog

In pratica si può definire il proprio 'Tipo di revisione' utilizzando @RevisionEntity annotazione, e quindi implementare un'interfaccia RevisionListener inserire i dati di controllo aggiuntivi, come utente corrente e il funzionamento di alto livello. Di solito questi sono tirati dal contesto ThreadLocal.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top