Я пытаюсь вычислить среднюю разницу дат, используя QueryDSL.
Я создал небольшой проект, чтобы продемонстрировать, чего я пытаюсь достичь, в упрощенный способ (реальный запрос намного сложнее, с множеством предложений соединения/где/сортировки). У нас есть Customer с полем birthDate
, и мы пытаемся получить средний возраст наших клиентов в секундах. Нам также нужен максимальный возраст, но давайте сосредоточимся на среднем для этого поста.
Я попытался написать этот запрос, используя 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()
, но он не возвращает правильное значение. Если мы хотим получить разницу дат в секундах, кажется, нам нужно найти какой-то способ вызова функций разницы даты/времени для конкретной базы данных, а не просто использовать знак минус.
К сожалению, вычисление разницы в дате кажется невозможным в 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, как нам сгенерировать и
QCustomer
, иSCustomer
?QCustomer
в настоящее время создается из объекта Customer с помощью плагина com.mysema.maven:apt-maven-plugin. Если я правильно понял, мне нужно использовать другой плагин (com.querydsl:querydsl-maven-plugin) для создания запроса типаSCustomer
?При просмотре querydsl-sql-example я не вижу никакого класса сущности, поэтому я предполагаю, что типы запросов генерируются QueryDSL из схемы базы данных? Есть ли способ вместо этого сгенерировать тип запроса SCustomer из объекта, как мы делаем с querydsl-jpa?
Если мы используем querydsl-sql, есть ли способ повторно использовать наши предложения предикатов/сортировок/объединений querydsl-jpa в запросе querydsl-sql? Или нам нужно дублировать этот код, используя классы, специфичные для querydsl-sql?
Я также рассматриваю возможность создания функции базы данных, которая делегирует
TIMESTAMPDIFF(SECOND, x, y)
, но она не очень переносима...Я что-то упускаю? Есть ли более простой способ сделать то, что я пытаюсь сделать?