使用 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 从中受益。
这是我的问题:
是否可以使用 querydsl-jpa 计算平均日期差异,使其可以使用 JPA 2.1 支持(可能使用 Expressions.numberTemplate()
)调用本机数据库函数?还是我们被迫使用 querydsl-sql?
如果我们必须使用querydsl-sql,我们如何生成QCustomer
和SCustomer
? QCustomer
当前是使用插件“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 一样?
如果我们使用 querydsl-sql,有没有办法在 querydsl-sql 中“重新使用”我们的 querydsl-jpa 谓词/排序/连接子句询问?或者我们是否必须使用 querydsl-sql-specific classes 来复制该代码?
我也在考虑创建一个委托给 TIMESTAMPDIFF(SECOND, x, y)
的数据库函数,但它不是很便携...
我是不是漏掉了什么?有没有更简单的方法来做我想做的事情?
使用模板表达式,您应该能够将任何自定义 JPQL 片段注入到 Querydsl 查询中。这应该可以回答您的第一个问题。
在同一项目中同时使用 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 从中受益。
这是我的问题:
是否可以使用 querydsl-jpa 计算平均日期差异,使其可以使用 JPA 2.1 支持(可能使用
Expressions.numberTemplate()
)调用本机数据库函数?还是我们被迫使用 querydsl-sql?如果我们必须使用querydsl-sql,我们如何生成
QCustomer
和SCustomer
?QCustomer
当前是使用插件“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 一样?
如果我们使用 querydsl-sql,有没有办法在 querydsl-sql 中“重新使用”我们的 querydsl-jpa 谓词/排序/连接子句询问?或者我们是否必须使用 querydsl-sql-specific classes 来复制该代码?
我也在考虑创建一个委托给
TIMESTAMPDIFF(SECOND, x, y)
的数据库函数,但它不是很便携...我是不是漏掉了什么?有没有更简单的方法来做我想做的事情?
使用模板表达式,您应该能够将任何自定义 JPQL 片段注入到 Querydsl 查询中。这应该可以回答您的第一个问题。
在同一项目中同时使用 querydsl-jpa 和 querydsl-sql 是可能的,但会增加一些复杂性。