我有一个经过审计的实体 A。实体 A 包含字段“名称”和实体 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 还从修订版 #1 获取与此 A 相关的实体 B 的集合。这是 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)
但实际上我需要 NULL 作为实体 B 的集合,以防它在修订版 #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。但是如果请求的修订不存在(在我的情况下#2),我找不到不查询 B 的标准解决方案。所以查询应该如下所示:
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。
有人可以帮忙解决这个问题吗?是否需要添加标准配置/注释以避免第二个 SUBSELECT?