关于jpql:使用querydsl-jpa / querydsl-sql的平均日期差

Average date difference using querydsl-jpa / querydsl-sql

我正在尝试使用QueryDSL计算平均日期差。

我创建了一个小项目,以简化的方式演示我要完成的工作(真正的查询要复杂得多,其中包含大量的joins / where / sort子句)。我们有一个带birthDate字段的Customer类,并且我们试图获取以秒为单位的客户的平均年龄。我们还需要最大年龄,但让我们关注这篇文章的平均年龄。

我尝试使用querydsl-jpa编写此查询,但失败并显示一个模糊错误:

1
2
3
4
5
java.lang.NullPointerException
        at org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions$AvgFunction.determineJdbcTypeCode(StandardAnsiSqlAggregationFunctions.java:106)
        at org.hibernate.dialect.function.StandardAnsiSqlAggregationFunctions$AvgFunction.render(StandardAnsiSqlAggregationFunctions.java:100)
        at org.hibernate.hql.internal.ast.SqlGenerator.endFunctionTemplate(SqlGenerator.java:233)
        [...]

我还尝试了其他方法,例如使用NumberTemplate.create(Double.class,"{0} - {1}", DateExpression.currentDate(), customer.birthDate).avg(),但是它没有返回正确的值。如果要以秒为单位获取日期差,则似乎需要找到某种方法来调用特定于数据库的日期/时间差函数,而不仅仅是使用减号。

可悲的是,在JPQL中似乎无法计算日期差,因此我猜querydsl-jpa也有局限性。因此,我们将不得不编写本机SQL查询,或者找到一些技巧以使QueryDsl生成的JPQL调用本机数据库函数。

JPA 2.1添加了对调用数据库函数的支持,但是存在一个问题:MySQL函数的形式为TIMESTAMPDIFF(SECOND, '2012-06-06 13:13:55', '2012-06-06 15:20:18')。如果第一个参数(SECOND)是字符串,则可能会出现这种情况,但它似乎是对某种常量的引用,并且生成不带第一个参数的JPQL似乎很复杂。

QueryDSL添加了对日期差异的支持,但是似乎大多数代码都驻留在querydsl-sql项目中,因此我想知道是否可以通过querydsl-jpa受益于此。

这是我的问题:

  • 是否可以使用querydsl-jpa计算平均日期差,是否可以使用JPA 2.1支持(也许使用Expressions.numberTemplate())调用本机数据库函数?还是我们被迫使用querydsl-sql?

  • 如果必须使用querydsl-sql,如何生成QCustomerSCustomerQCustomer当前是使用插件" com.mysema.maven:apt-maven-plugin"从客户实体生成的。如果我理解正确,则必须使用其他插件(com.querydsl:querydsl-maven-plugin)生成SCustomer查询类型?

    当查看querydsl-sql-example时,我没有看到任何实体类,因此我猜查询类型是QueryDSL由数据库模式生成的?有没有办法像从querydsl-jpa一样从实体生成SCustomer查询类型?

  • 如果我们使用querydsl-sql,是否有办法"重用" querydsl-sql查询中的querydsl-jpa谓词/ sorts / joins子句?还是我们必须使用querydsl-sql特定的类来复制该代码?

  • 我也在考虑创建一个委托给TIMESTAMPDIFF(SECOND, x, y)的数据库函数,但是它不是非常可移植的...

  • 我想念什么吗?有没有更简单的方式来做我想做的事情?


  • 使用模板表达式,您应该能够将所有自定义JPQL代码片段注入Querydsl查询中。 那应该回答你的第一个问题。

    可以在同一项目中同时使用querydsl-jpa和querydsl-sql,但会增加一些复杂性。