0

我有一个经过审计的实体 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?

4

1 回答 1

0

Envers 中没有在请求时不加载相关实体的选项。但是,并非总是延迟加载 B 实体(无论关系上的注释如何),因此如果您不想执行加载它们的查询,只需不要访问该字段。

如果您想要更好的读取性能,您可能还想查看有效性审计策略,请参阅http://docs.jboss.org/hibernate/core/4.1/devguide/en-US/html/ch15.html#d5e4085。它的读取速度更快,但写入速度较慢。

于 2013-02-08T11:25:49.213 回答