Hibernate支持count(*) over()吗?

7

我希望避免创建一个用于计数的单独查询和一个用于实际查询的查询。我发现SesssionImpl :: createQuery对于复杂查询需要相当长的时间,通过组合计数和主要查询,我可以消除一个createQuery调用。

在SQL中,我可以做这样的事情

select count(*) over(), col_A, col_B 
from TABLE_XX 
where col_C > 1000

这个能在Hibernate中实现吗?

(我想避免使用本地SQL,而是坚持使用HQL和Detached Criteria。使用本地SQL会使Hibernate失去意义。我的系统必须支持Oracle和Sybase两种数据库)


1
你总是可以使用本地 SQL。我猜你想避免那个? - Daniel Kaplan
是的,我正在尝试避免使用本地SQL,而是坚持使用HQL和Detached Criteria。使用本地SQL会破坏使用Hibernate的目的。 - user2596860
你使用的底层数据库是什么? - Daniel Kaplan
我的系统必须支持Oracle和Sybase。 - user2596860
1
只需使用本地SQL,无论是否使用Hibernate。分析函数是标准的,并且它们受到大多数现代RDBMS实现的支持。实际上,最好始终使用纯SQL而不是“面向对象查询”,因为它们在工具之间更易于移植,易于测试,没有生成的混淆,并且速度更快。 - jbaliuka
2个回答

3
Hibernate的@Formula注释可能作为解决方法。在您的@Entity中提供一个额外的列来表示计数,使用带有@Formula的注释进行标注,其中包含COUNT OVER查询:
@Formula("count(*) over ()")
private Integer totalResults;

使用这种方法,Hibernate 会在生成的 SQL 中做一些调整,因此您可能还需要注册一个 Interceptor 来清理 SQL:
public class CountOverQueryInterceptor extends EmptyInterceptor {

    private static final long serialVersionUID = -2980622815729060717L;

    @Override
    public String onPrepareStatement(String sql) {
        return super.onPrepareStatement(cleanCountOver(sql));
    }

    /**
     * Cleans the "{@code count(*) over ()}" query fragment from Hibernate's sql
     * decoration "{@code count(*) <alias>.over ()}".
     */
    static String cleanCountOver(String sql) {
        return sql.replaceAll("(?i) (count)\\(\\*\\) \\w+\\.(over) \\(\\)", " $1(*) $2 () ");
    }

}

除了明确的Hibernate依赖(而不是纯JPA),还有一个缺点,即此列将默认加载,这可能会在不需要计数的查询中增加一些不必要的开销。可以将该列设置为可选,并进行延迟加载,但这需要字节码插装并增加更多的复杂性。
@Formula("count(*) over ()")
@Basic(optional = true, fetch = FetchType.LAZY)
private Integer totalResults;

1

您可以将此用于以下用途:

return (Number) session.createCriteria("Book").setProjection(Projections.rowCount()).uniqueResult();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接