Envers @ManyToMany子查询

时间:2013-02-07 10:11:48

标签: subquery hibernate-envers

我有一个经过审核的实体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也从版本#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中)并通过以下方式定义A B关系:

@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?

1 个答案:

答案 0 :(得分:0)

Envers中没有选项可以在请求时不加载相关实体。但是,B实体始终懒惰地加载(无论关系上的注释),因此如果您不想执行加载它们的查询,则只需不访问该字段。

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