최대 절전 모드 엔터티의 기존 데이터로 개정 테이블을 채우십시오.

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

문제

기존 최대 절전 모드 엔티티에 Envers를 추가하고 있습니다. 모든 것이 감사하는 한 모든 것이 원활하게 작동하지만 개정 테이블이 기존 데이터로 채워지지 않기 때문에 쿼리는 다른 문제입니다. 다른 사람이 이미이 문제를 해결 했습니까? 기존 테이블로 개정 테이블을 채우는 방법을 찾았 을까요? 그냥 물어볼 것이라고 생각했는데, 다른 사람들이 유용 할 것이라고 확신합니다.

도움이 되었습니까?

해결책

당신은 할 필요가 없습니다.
AuditQuery는 다음의 개정 및 데이터 개정을 모두 얻을 수 있습니다.

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

이것은 객체 목록을 반환하는 쿼리를 구성합니다 [3]. FISRT 요소는 귀하의 데이터이고, 두 번째는 개정 엔티티이고 세 번째는 개정 유형입니다.

다른 팁

우리는 일련의 원시 SQL 쿼리를 실행하여 기존 엔티티를 동시에 만들었던 것처럼 "삽입"하는 일련의 원시 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

주목하십시오 Revtype 가치는입니다 0 삽입을 표시합니다 (수정과 반대로).

Envers를 사용하는 경우이 카테고리에서 문제가 발생합니다. 타당성 사우 도트 스트레이트 Envers가 Enabled가 아닌 다른 데이터가 생성되었습니다.

우리의 경우 (Hibernate 4.2.8.final) 기본 객체 업데이트는 "엔티티의 이전 개정판을 업데이트 할 수없고"([org.hibernate.assertionfailure] hhh000099).

이 토론/설명을 찾는 데 시간이 걸렸습니다.

감사 기록이없는 타당성

우리는 다음과 같이 감사 로그를 기존 데이터로 채우는 문제를 해결했습니다.

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

내 데이터 소스의 구성 (스프링을 통해) :

<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 주석을 사용하여 자신의 '개정 유형'을 정의한 다음 현재 사용자 및 고 레벨 작업과 같은 추가 감사 데이터를 삽입하기 위해 개정 리스너 인터페이스를 구현할 수 있습니다. 일반적으로 그것들은 ThreadLocal 컨텍스트에서 가져옵니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top