監査対象のエンティティ A があります。エンティティ A は、フィールド 'name' とエンティティ B のコレクション (多対多の関係として注釈が付けられています) を保持しています。A のインスタンス、定義された名前、エンティティ B のコレクションを作成し、すべてを DB に保存します。これはリビジョン 1 です。次に、Aの名前を変更してDBで更新しました。これはリビジョン 2 です。次のメソッドを使用して、リビジョン #2 でクラス A のすべてのエンティティを取得します
List<A> list = getAuditReader().createQuery().forEntitiesAtRevision(A.class, 2)
.add(AuditEntity.revisionNumber().eq((int) revisionId)).getResultList();
リビジョン #2 でエンティティ A を取得しますが、Envers はこの A に関連するエンティティ B のコレクションもリビジョン #1 から取得します。Envers で使用されるクエリの例を次に示します。
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id
AND b_aud.rev=(SELECT max(b_aud2.rev)) FROM b_aud AS b_aud2 WHERE b_aud2.rev<=2 AND b_aud.id=b_aud2.id)
AND a_b_aud.rev=(SELECT max(a_b_aud2.rev)) FROM a_b_aud AS a_b_aud2 WHERE a_b_aud2.rev<=2 AND a_b_aud.a_id=a_b_aud2.a_id AND a_b_aud.b_id=a_b_aud2.b_id)
しかし、実際には、リビジョン #2 で変更がなかった場合 (パフォーマンスの問題のため)、エンティティ B のコレクションとして NULL が必要です。
このクエリには 2 つの副選択があります。また、A (C、D、E、F) に関連するエンティティのコレクションが複数あり、b_aud と a_b_aud ごとに約 10 万行ある場合、上記のクエリには多くの時間がかかります。エンティティ B を監査対象外として定義し (つまり、@Audited アノテーションを B に追加しませんでした)、AB 関係を次のように定義しました。
@ManyToMany
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
@JoinTable(name = "a_b", joinColumns = @JoinColumn(name = a_id))
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
public Set<B> getBs();
最初の SUBSELECT を修正します。しかし、要求されたリビジョンが存在しない場合に B を照会しないという標準的な解決策を見つけることができません (私の場合は #2)。したがって、クエリは次のようになります。
SELECT a_b_aud.a_id, a_b_aud.b_id
FROM a_b_aud CROSS JOIN b_aud
WHERE a_b_aud.b_id=b_aud.id b_aud.rev=2 AND a_b_aud.rev=2
私が見つけた唯一の解決策は、ネイティブ SQL クエリを使用し、hibernate テンプレートを使用して実行することです。次に、ResultTransformer を使用して結果値をエンティティ A に変換します。
誰でもこの問題を解決できますか? 2 番目の SUBSELECT を回避するために追加する必要がある標準的な構成/注釈はありますか?