如何配置 Hibernate Envers 以避免实体修订查询中的某些集合(连接表)
Posted
技术标签:
【中文标题】如何配置 Hibernate Envers 以避免实体修订查询中的某些集合(连接表)【英文标题】:How to configure Hibernate Envers to avoid certain collections (join tables) in entity revision queries 【发布时间】:2018-02-21 08:04:28 【问题描述】:我正在使用 Hibernate Envers 4.2
,我想仅从实体中的某些集合中获取实体的修订版本。
但我可以看到为实体中的所有集合触发的休眠查询会导致性能问题。
也无法在此特定查询中对集合使用 @NotAudited
注释以避免在此特定查询中,因为在这些集合的其他场景中需要审计。
例如,如果我的审核实体将这两个连接作为集合。 但是我希望查询获取我的实体的修订版以仅获取地址信息并忽略订单信息,这可能吗?我不想用@NotAudited 注释订单信息,因为在其他情况下可能需要历史信息。
@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() return address;
@OneToMany
@JoinColumn(name="CUST_ID")
public Set<Order> getOrders() return orders;
【问题讨论】:
您能改用基于投影的查询来解决您的问题吗? 我需要获取一些连接表的详细信息。我无法对 Auditquery 中的连接表进行投影。尽管已审核连接表,但我收到错误为“属性未解决” 您能否展示您的实体和代码,以便我们了解您在这里尝试的确切内容? 您确定没有调用导致集合水合的#getOrders()
方法的代码吗? AFAIK,该集合应该在调用 getter 方法时延迟初始化。
当您查询已审计的历史记录时,任何明确标记为@NotAudited
的内容都将有效地为空,因为您已明确指定不需要跟踪该属性。重要的是要记住,审计查询不会像 ORM 那样返回“真实”实体,而只是返回仅填充了相应审计属性的实体类的实例;而已。如果一个集合被标记为要审核,那么将为该关联构造一个查询生成器,但该集合的结果并不总是急切地加载。
【参考方案1】:
与this Hibernate documentation example 一样,如果我有一个Customer
与Address
关联:
@Audited( withModifiedFlag = true )
@Entity(name = "Customer")
public class Customer
...
@ManyToOne(fetch = FetchType.LAZY)
private Address address;
我使用this query查询修订:
List<Customer> customers = AuditReaderFactory
.get( entityManager )
.createQuery()
.forRevisionsOfEntity( Customer.class, false, true )
.add( AuditEntity.id().eq( 1L ) )
.add( AuditEntity.property( "lastName" ).hasChanged() )
.getResultList();
Envers 只查询Customers
,而不是Address
:
select
c.id as id1_3_0_,
c.REV as REV2_3_0_,
defaultrev1_.REV as REV1_4_1_,
c.REVTYPE as REVTYPE3_3_0_,
c.REVEND as REVEND4_3_0_,
c.created_on as created_5_3_0_,
c.createdOn_MOD as createdO6_3_0_,
c.firstName as firstNam7_3_0_,
c.firstName_MOD as firstNam8_3_0_,
c.lastName as lastName9_3_0_,
c.lastName_MOD as lastNam10_3_0_,
c.address_id as address11_3_0_,
c.address_MOD as address12_3_0_,
defaultrev1_.REVTSTMP as REVTSTMP2_4_1_
from
Customer_AUD c cross
join
REVINFO defaultrev1_
where
c.id = ?
and c.lastName_MOD = ?
and c.REV=defaultrev1_.REV
order by
c.REV asc
-- binding parameter [1] as [BIGINT] - [1]
-- binding parameter [2] as [BOOLEAN] - [true]
除非您像这样导航关联:
AuditQuery innerJoinAuditQuery = AuditReaderFactory
.get( entityManager )
.createQuery()
.forEntitiesAtRevision( Customer.class, 1 )
.traverseRelation( "address", JoinType.INNER );
Hibernate Envers 不应将它们包含在 SQL 修订查询中。
【讨论】:
我没有使用 traverseRelation。我正在使用方法 AuditReader.find(entity, uuid, revisonNum) 。我看到为实体中的所有集合触发了单独的“选择查询”。集合注释如下。我也尝试过惰性获取,但观察到为所有集合触发的选择查询会导致修订查询变慢。@ManyToOne(cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
我也尝试了 Lazy fetch,但在查询修订时仍然观察到为实体中的所有集合触发的选择查询。
您可以使用原生查询作为戴尔。 Invers 表毕竟只是表。
我观察到 Envers 表只保存每个版本的修改数据,但我需要每个版本的完整信息。对于每个版本,有许多连接需要导航并转换回 Java 对象,并且使用本机查询是不可行的。
让我们continue this discussion in chat.以上是关于如何配置 Hibernate Envers 以避免实体修订查询中的某些集合(连接表)的主要内容,如果未能解决你的问题,请参考以下文章
审计没有 Hibernate Envers 的 java 实体
Hibernate Envers:初始化 Envers 代理