使用 querydsl-jpa / querydsl-sql 的平均日期差异

Average date difference using querydsl-jpa / querydsl-sql

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

我用 birthDate 字段创建了 a small project to demonstrate what I'm trying to accomplish, in a simplified manner (the real query is a lot more complex, with tons of joins / where / sort clauses). We have a Customer class,我们正在尝试获取客户的平均年龄(以秒为单位)。我们还想要最大年龄,但让我们关注这个 post.

的平均值

I tried writing this query using querydsl-jpa,但失败并出现一个模糊错误:

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(),但 return 不是正确的值。如果我们想获得以秒为单位的日期差异,看来我们需要找到一些方法来调用特定于数据库的 date/time 差异函数,而不仅仅是使用减号。

遗憾的是,computing a date difference doesn't seem to be possible in JPQL,所以我猜 querydsl-jpa 也有局限性。所以我们必须编写一个原生 SQL 查询,或者找到一些 hack 来让 QueryDsl 生成的 JPQL 调用原生数据库函数。

JPA 2.1 added support for invoking database functions,但有一个问题:MySQL 函数采用 TIMESTAMPDIFF(SECOND, '2012-06-06 13:13:55', '2012-06-06 15:20:18') 的形式。如果第一个参数(SECOND)是一个字符串可能是可能的,但它似乎是对某种常量的引用,并且生成第一个参数不带引号的JPQL似乎很复杂。

QueryDSL added support for date differences,但似乎大部分代码都驻留在 querydsl-sql 项目中,所以我想知道我是否可以通过 querydsl-jpa 从中受益。

这是我的问题:

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

  2. 如果我们必须使用querydsl-sql,我们如何生成QCustomerSCustomerQCustomer 当前是使用插件“com.mysema.maven:apt-maven-plugin”从客户实体生成的。如果我理解正确,I have to use a different plugin (com.querydsl:querydsl-maven-plugin) 生成 SCustomer 查询类型?

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

  3. 如果我们使用 querydsl-sql,有没有办法在 querydsl-sql 中“重新使用”我们的 querydsl-jpa 谓词/排序/连接子句询问?或者我们是否必须使用 querydsl-sql-specific classes 来复制该代码?

  4. 我也在考虑创建一个委托给 TIMESTAMPDIFF(SECOND, x, y) 的数据库函数,但它不是很便携...

  5. 我是不是漏掉了什么?有没有更简单的方法来做我想做的事情?

使用模板表达式,您应该能够将任何自定义 JPQL 片段注入到 Querydsl 查询中。这应该可以回答您的第一个问题。

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