我有 3 个实体,我们称它们为
Parent
、Child1
和 Child2
。 Parent
与另外两个有 @OneToOne
关系:
@OneToOne(mappedBy = "team", fetch = FetchType.LAZY, optional = false)
使用
JpaSpecificationExecutor
并传递 Specification
和 Pageable
对象来执行查询。这两个关系都指定由 Specification
获取,因此生成的 SQL 看起来像这样:
select <a lot of fields from p, c1, c2>
from parent p
join child1 c1 <on something>
join child2 c2 <on something>
order by <some timestamp field>
limit M offset N
当结果数量超过单个页面所能容纳的数量时就会出现问题,因此 JPA 必须执行计数查询。
SimpleJpaRepository
实现这一点的方法是简单地应用您为新计数查询提供的相同规范。
这会导致异常:
org.hibernate.query.SemanticException: Query specified join fetching, but the owner of the fetched association was not present in the select list [SqmSingularJoin(Parent(332551168492391).child1(332551168541736) : child1)]]
我认为这是有道理的,因为生成的查询看起来像这样:
select count(*)
from parent p
join child1 c1 <on something>
join child2 c2 <on something>
order by <some timestamp field>
也就是说,我们连接表,但实际上并没有从中选择任何内容。
那么从这里开始的最佳方法是什么?
当我稍微更改标题后,就会出现更多类似的问题,我偶然发现了这个答案。由于我无法从 JPQL 访问
countQuery
,这似乎是最好的解决方案。不过,我将其修改为不那么脆弱:
if (Parent.class.isAssignableFrom(query.getResultType())) {
root.fetch("child1");
root.fetch("child1");
} else {
root.join("child2");
root.join("child2");
}
这似乎工作得很好,甚至在计数查询中省略了连接。只是不要忘记在支票中包含任何可能的预测(如果您使用的话)。