休眠是否支持count(*)over()

时间:2014-02-06 23:59:39

标签: java sql hibernate window-functions

我正在尝试阻止为count创建一个单独的查询,为实际查询创建一个查询。我发现SesssionImpl :: createQuery需要相当长的时间来进行复杂的查询,通过组合count和主查询,我可以消除一个createQuery调用。

在SQL中我可以做类似

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

这可以在休眠中实现吗?

(我正在尝试避免本机sql并坚持使用HQL和分离标准。使用本机SQL会破坏使用hibernate的目的。我的系统必须同时支持Oracle和Sybase)

2 个答案:

答案 0 :(得分:2)

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)之外,还有另一个缺点,即默认情况下会加载此列,这可能会为不需要计数的查询增加一些不必要的开销。可以使列成为可选的lazily loaded,但这需要字节码检测并进一步增加复杂性。

@Formula("count(*) over ()")
@Basic(optional = true, fetch = FetchType.LAZY)
private Integer totalResults;

答案 1 :(得分:1)

您可以将其用于: -

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