QueryDSL 4 与 RowNumber Window 功能

Posted

技术标签:

【中文标题】QueryDSL 4 与 RowNumber Window 功能【英文标题】:QueryDSL 4 with RowNumber Window function 【发布时间】:2017-04-06 06:39:31 【问题描述】:

我正在使用带有 spring 数据的查询 dsl。

环境:

    <querydsl-apt.version>4.1.4</querydsl-apt.version>
    <querydsl-jpa.version>4.1.4</querydsl-jpa.version>
    <querydsl-sql.version>4.1.4</querydsl-sql.version>
    <spring>4.3.3.RELEASE</spring>

查询:

JPAQueryFactory query = new JPAQueryFactory(getEntityManager());

SimpleExpression<Long> rowNumber = SQLExpressions.rowNumber()
        .over()
        .orderBy(qServiceExecution.updatedAt.asc()).as("rowNumber");

List<Tuple> response = query.select(qServiceExecution.id, SQLExpressions.rowNumber()
                .over()
                .orderBy(qServiceExecution.updatedAt.asc()))
        .from(qServiceExecution)
        .fetch();

例外:

Root cause: java.lang.IllegalArgumentException: No pattern found for ROWNUMBER
    at com.querydsl.core.support.SerializerBase.visitOperation(SerializerBase.java:280) ~[querydsl-core-4.1.4.jar:na]
    at com.querydsl.jpa.JPQLSerializer.visitOperation(JPQLSerializer.java:437) ~[querydsl-jpa-4.1.4.jar:na]
    at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:231) ~[querydsl-core-4.1.4.jar:na]
    at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:31) ~[querydsl-core-4.1.4.jar:na]



Spring error: No pattern found for ROWNUMBER; nested exception is java.lang.IllegalArgumentException: No pattern found for ROWNUMBER
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:491) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.3.3.RELEASE.jar:4.3.3.RELEASE]

查询 DSL 文档:http://www.querydsl.com/static/querydsl/latest/reference/html/ch02s03.html#d0e1276

其他堆栈溢出问题:QueryDSL Window functions

有什么建议吗?

【问题讨论】:

很久以前了,但您还记得您是如何解决此问题的吗?有什么建议吗?! 【参考方案1】:

窗口函数不包含在 JPQL 规范中,因此在任何 JPA 实现中都不可用。您可以使用custom functions 自己注册这些函数。

但是,在此之后,这些功能仍然无法在 QueryDSL 中访问。您从这里的SQLExpressions 中窃取以获取窗口表达式。这些方法存在于SQLExpressions 中是有原因的:它们仅适用于querydsl-sql 而不适用于querydsl-jpa(同样,因为JPA 本身不支持窗口函数)。因此,在注册自定义函数后,您仍然需要扩展 JPQLTemplates 以包含自定义窗口函数的模板。

你会这样做:

public class MyTemplates extends JPQLTemplates 

    public MyTemplates() 
        add(SQLOps.ROWNUMBER, "ROW_NUMBER(0)");
    


然后按如下方式使用:

new JPAQuery(entityManager, new MyTemplates()).from(entity).select(rowNumber())

但是,由于中间有 Spring 集成,我认为模板更难以绑定到查询。


或者,您可以查看 blaze-persistence-querydsl 扩展,它对 JPQL 的窗口函数(和许多其他功能)提供开箱即用的支持。例如:

QCat cat = QCat.cat;

BlazeJPAQuery<Tuple> query = new BlazeJPAQuery<Tuple>(entityManager, criteriaBuilderFactory).from(cat)
    .select(cat.name, JPQLNextExpressions.rowNumber(), JPQLNextExpressions.lastValue(cat.name).over().partitionBy(cat.id));

List<Tuple> fetch = query.fetch();

【讨论】:

【参考方案2】:

抱歉迟到了,但我遇到了同样的问题,我通过添加there的配置文件解决了这个问题

然后注入 CriteriaBuilderFactory

 @Inject
CriteriaBuilderFactory cbf; 

一开始,然后用这样的窗口函数编写任何查询

QProductHistory his =QProductHistory.productHistory;
SimpleExpression<Long> rown =  JPQLNextExpressions.rowNumber().over().partitionBy(his.esn).as("rown");
BlazeJPAQuery<Tuple> bl_qry = new BlazeJPAQuery<Tuple>(entityManager, cbf).from(his)
            .select(his.esn, rown);

    List<Tuple> fetch = bl_qry.fetch();

【讨论】:

以上是关于QueryDSL 4 与 RowNumber Window 功能的主要内容,如果未能解决你的问题,请参考以下文章

NoSuchMethodException QueryDSL 与 Spring Boot 和 Spring Data Mongo

SpringBoot 2.6.1 与 Querydsl Mongodb 不兼容?

oracle字段按rownumber 排序不准确怎么解决

如何使用 Querydsl 更新 JPA 实体?

SQL rownumber partition 取范围数据进行分组

Java 11 + QueryDSL 4 + Gradle 5 + SpringBoot 2.1-不生成 QClasses