【发布时间】:2016-11-23 15:18:07
【问题描述】:
我在 hibernate-jpa-2.1 中将 NamedQuery 重写为 CriteriaQuery。原始 NamedQuery 包含一个引用别名子查询的 order by 子句。
select
new ItemDto (
item.id,
item.number,
(select count(*) from ClickEntity as click where click.item.id = item.id) as clickCount
)
from ItemEntity as item
order by clickCount desc
我找不到任何方法来使用别名来引用 clickCount 字段,所以我想我不妨在这两个地方都使用子查询:
public List<ItemDto> getItems() {
...
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<ItemDto> query = criteriaBuilder.createQuery(ItemDto.class);
Root<ItemEntity> item = query.from(ItemEntity.class);
query
.select(
cb.construct(ItemDto.class,
item.get("id"),
item.get("number"),
getClickCount(cb, query, item).getSelection()
)
)
.orderBy(cb.desc(getClickCount(cb, query, item).getSelection()))
TypedQuery<ItemDto> typedQuery = entityManager.createQuery(query);
return typedQuery.getResultList();
}
private Subquery<Long> getClickCount(CriteriaBuilder cb, CriteriaQuery<ItemDto> query, Root<ItemEntity> item) {
Subquery<Long> subquery = query.subquery(Long.class);
Root<ClickEntity> click = subquery.from(ClickEntity.class)
return subquery
.select(cb.count(click.get("id")))
.where(cb.equal(click.get("item").get("id"), item.get("id")));
}
但是,当调用 getItems() 时,Hibernate 在创建 TypedQuery 时会抛出以下异常:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: query [...]
解析后的查询如下:
select new ItemDto(
generatedAlias0.id,
generatedAlias0.number,
(select count(generatedAlias1.id) from ClickEntity as generatedAlias1 where( generatedAlias1.item.id=generatedAlias0.id ))
)
from ItemEntity as generatedAlias0
order by
(select count(generatedAlias2.id) from ClickEntity as generatedAlias2 where( generatedAlias2.item.id=generatedAlias0.id )) desc
尽管抛出了错误,但这个查询对我来说看起来不错。我已经在没有 order by 子句的情况下对其进行了测试,然后它按预期工作,因此该错误肯定是由该子句引起的。但是,由于子查询显然有效,我很难弄清楚问题出在哪里。
我尝试过/考虑过的:
- 使用@PostConstruct 设置ItemEntity 的@Transient 字段;这不是一个选项,因为在实际应用中,clickCount 的值取决于 Date 参数。
- 检索结果后排序;这不是一个选项,因为需要在应用(可选)限制参数之前进行排序
- 不使用 getSelection()。这具有相同的效果(甚至是相同的查询)。
所以,我想知道,Hibernate 是否真的支持这种方法,还是我错过了一个(可能更简单的)替代方法来使用子查询的结果作为排序参数?
【问题讨论】: