2009-05-22 2 views
19

엔버를 기존의 최대 절전 엔티티에 추가하고 있습니다. 지금까지는 감사까지는 모든 것이 원활하게 진행되고 있지만 리비전 테이블에는 기존 데이터가 채워지지 않으므로 쿼리가 다른 문제입니다. 이미 다른 사람이이 문제를 해결 했습니까? 어쩌면 수정 테이블을 기존 테이블로 채울 수있는 방법을 찾았 을까요? 그냥 물어볼 것이라고 생각했는데 다른 사람들이 유용하다고 생각할 것입니다.하이버 네이트 엔티티의 기존 데이터로 리비전 테이블을 채 웁니다.

+0

어떻게 당신이 감사 작업을 얻고있다 :

때문에 교차 게시이 토론/설명을 찾을 걸 렸어요? 나는 심지어 멀리까지 얻을 수 없다 : ( –

+1

그것은 매우 간단하다, 단지 짧은 매뉴얼을 읽는다 : http://www.jboss.org/files/envers/docs/index.html – danieljimenez

+0

나는 이것에 대해 궁금해하고 있었지만, 나는 환경에 대한 감사 정보가 필요합니다.어떤 사용자와 그들이 어떻게 변경을 수행했는지 - 어떤 높은 수준의 사용자 작업이 변경 작업을 유발했는지. 명시 적 변경과 "부작용"변경을 확인할 수 있어야합니다. Envers가 이러한 요구를 처리하는지 알고 있습니까? – Pat

답변

5

필요하지 않습니다. 객체 [3]의 목록을 반환하는 쿼리를 구성합니다

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

이 :
AuditQuery는에 의해 RevisionEntity 및 데이터 수정을 모두 얻을 수 있습니다. Fisrt 요소는 데이터이고 두 번째 요소는 수정 엔터티이고 세 번째 요소는 수정 유형입니다.

+1

더 확장 할 수 있습니까? 수정 엔터티가 null 인 경우 AuditQuery에서 반환 한 배열의 첫 번째 요소 만 사용해야한다고 말하고 있습니까? – Rezler

1

귀하의 추가 감사 데이터, 현재 사용자와 높은 수준의 작업과 같은 을 삽입 할 RevisionListener 인터페이스를 기본적으로 당신이 @RevisionEntity 주석, 을 사용하여 자신의 '수정 유형'을 정의 할 수 있습니다 http://www.jboss.org/files/envers/docs/index.html#revisionlog

를 살펴보고 다음 구현 . 일반적으로 ThreadLocal 컨텍스트에서 가져옵니다.

12

우리는 일련의 원시 SQL 쿼리를 실행하여 초기 데이터를 채워서 모든 기존 엔터티를 방금 생성 한 것처럼 마치 "삽입"합니다. (변형 반대) REVTYPE 값이 0이 인서트를 나타내는 것을

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 

참고 : 예를 들어. 다음과 같이

+0

이 접근법은'javax.persistence.EntityNotFoundException : id x' 예외가있는 을 찾을 수 없음을 해결하는 데 효과적입니다. 특히 히스토리 네이트 외부에로드 된 '정적'데이터에 대한 참조 (SO : 5261139) (http://stackoverflow.com/questions/5261139/hibernate-envers-initializing-envers-proxies)의 하위 데이터를 올바르게로드 할 때 이 예외가 발생합니다. (현재 최대 절전 모드 4.2). – user598656

2

우리는 기존의 데이터와 감사 로그를 채우는 문제를 해결 한 :

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

ps : 단순화 된 예입니다. 그것은 밖으로 작동하지 않습니다하지만 그것은 작동 솔루션을 향해 당신을 안내 할 것입니다.

5

Envers ValidityAuditStrategy을 사용하고 있고 Envers가 활성화되지 않은 상태에서 생성 된 데이터가있는 경우이 카테고리에 문제가 있습니다.

우리의 경우 (Hibernate 4.2.8.Final) 기본 개체 업데이트는 "엔티티에 대한 이전 버전을 업데이트 할 수 없습니다."([org.hibernate.AssertionFailure] HHH000099로 기록됨) throw합니다.

ValidityAuditStrategy with no audit record

관련 문제