24

既存の休止状態のエンティティにエンバーを追加しています。監査に関してはすべてがスムーズに機能していますが、リビジョンテーブルに既存のデータが入力されていないため、クエリは別の問題です。他の誰かがすでにこの問題を解決しましたか?リビジョンテーブルに既存のテーブルを追加する方法を見つけたのではないでしょうか。私が尋ねると思っただけで、他の人がそれが役に立つと思うと確信しています。

4

6 に答える 6

17

一連の生の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であることに注意してください。

于 2011-12-01T21:08:58.870 に答える
7

Envers ValidityAuditStrategyを使用していて、Enversが有効になっていない場合以外に作成されたデータがある場合、このカテゴリで問題が発生します。

私たちの場合(Hibernate 4.2.8.Final)、基本的なオブジェクトの更新は「エンティティの以前のリビジョンを更新できません」([org.hibernate.AssertionFailure] HHH000099としてログに記録されます)をスローします。

このディスカッション/説明を見つけるのに少し時間がかかりましたので、クロスポストします:

監査レコードのないValidityAuditStrategy

于 2014-01-17T13:46:40.053 に答える
5

あなたはする必要はありません。
AuditQueryを使用すると、RevisionEntityとデータリビジョンの両方を次の方法で取得できます。

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

これにより、オブジェクト[3]のリストを返すクエリが作成されます。最初の要素はデータ、2番目はリビジョンエンティティ、3番目はリビジョンのタイプです。

于 2011-06-02T10:26:16.190 に答える
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 ); 
}     

私のデータソースの構成(Spring経由):

<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:これは単純化された例であることに注意してください。そのままでは機能しませんが、実用的なソリューションに向けてガイドします。

于 2012-08-23T09:01:51.957 に答える
1

http://www.jboss.org/files/envers/docs/index.html#revisionlogをご覧ください

基本的に、@ RevisionEntityアノテーションを使用して独自の「リビジョンタイプ」を定義し、RevisionListenerインターフェイスを実装して、現在のユーザーや高レベルの操作などの追加の監査データを挿入できます。通常、それらはThreadLocalコンテキストから取得されます。

于 2009-07-15T08:30:50.740 に答える
0

AuditReaderImpl次のように、findメソッドのフォールバックオプションを使用してを拡張できます。

    public class AuditReaderWithFallback extends AuditReaderImpl {

    public AuditReaderWithFallback(
            EnversService enversService,
            Session session,
            SessionImplementor sessionImplementor) {
        super(enversService, session, sessionImplementor);
    }

    @Override
    @SuppressWarnings({"unchecked"})
    public <T> T find(
            Class<T> cls,
            String entityName,
            Object primaryKey,
            Number revision,
            boolean includeDeletions) throws IllegalArgumentException, NotAuditedException, IllegalStateException {
        T result = super.find(cls, entityName, primaryKey, revision, includeDeletions);
        if (result == null)
            result = (T) super.getSession().get(entityName, (Serializable) primaryKey);
        return result;
    }
}

場合によっては、返品に関してさらにいくつかのチェックを追加できますnull。独自のファクトリも使用することをお勧めします。

    public class AuditReaderFactoryWithFallback {


    /**
     * Create an audit reader associated with an open session.
     *
     * @param session An open session.
     * @return An audit reader associated with the given sesison. It shouldn't be used
     * after the session is closed.
     * @throws AuditException When the given required listeners aren't installed.
     */
    public static AuditReader get(Session session) throws AuditException {
        SessionImplementor sessionImpl;
        if (!(session instanceof SessionImplementor)) {
            sessionImpl = (SessionImplementor) session.getSessionFactory().getCurrentSession();
        } else {
            sessionImpl = (SessionImplementor) session;
        }

        final ServiceRegistry serviceRegistry = sessionImpl.getFactory().getServiceRegistry();
        final EnversService enversService = serviceRegistry.getService(EnversService.class);

        return new AuditReaderWithFallback(enversService, session, sessionImpl);
    }

}
于 2021-07-27T09:21:21.790 に答える