好问题。这是我过去所做的(您已经提到的许多事情):
- 检查是否存在 SELECt 子句。
- 如果不是,请添加
select count(*)
- 否则,请检查它是否具有 DISTINCT 或聚合函数。如果您正在使用ANTLR来解析查询,则可以解决这些问题,但是涉及很多。您最好将整个过程包装为
select count(*) from ()
。
- 如果不是,请添加
- 去掉
fetch all properties
fetch
如果要将HQL解析为字符串,请从联接中删除。如果您是使用ANTLR真正解析查询,则可以将其left join
完全删除;检查所有可能的引用是很麻烦的。- 去掉
order by
- 根据您在1.2中所做的事情,您需要删除/调整
group by
/having
。
以上自然适用于HQL。对于Criteria查询,您只能做些限制,因为它不便于操作。如果您在Criteria之上使用某种包装层,则最终将得到ANTLR解析结果的(有限)子集,并且在这种情况下可以应用上面的大多数内容。
由于您通常会保留当前页面的偏移量和总计数,因此我通常会先使用给定的限制/偏移量运行实际查询,并且仅在
count(*)返回的结果数大于或等于限制且偏移量为零时才运行查询(在所有其他情况下,我要么
count(*)之前运行过,要么无论如何都要获得所有结果)。当然,对于并发修改,这是一种乐观的方法。
更新 (手工组装HQL)
我不太喜欢这种方法。当映射为命名查询时,HQL具有构建时错误检查的优势(从技术上来说,运行时是因为必须构建SessionFactory,尽管无论如何这通常是在集成测试中完成的)。当在运行时生成时,它会在运行时失败:-)进行性能优化也不是一件容易的事。
当然,同样的推理也适用于Criteria,但是由于定义良好的API(而不是字符串连接),因此更难解决。并行构建两个HQL查询(分页为一个,“全局计数”为一个)也会导致代码重复(并可能有更多的错误),或者迫使您在顶部编写某种包装层来为您完成。两种方法都不理想。而且,如果您需要从客户端代码执行此操作(如通过API进行操作),问题将变得更加严重。
实际上,我在这个问题上已经考虑了很多。Hibernate-Generic-
DAO的 Search API
似乎是一个合理的折衷方案。我对上述链接问题的回答中有更多详细信息。



