Средняя разница дат с использованием querydsl-jpa / querydsl-sql

Я пытаюсь вычислить среднюю разницу дат, используя 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.

Вот мои вопросы:

  1. Можно ли вычислить среднюю разницу дат с помощью querydsl-jpa, если он может вызывать собственные функции базы данных с использованием поддержки JPA 2.1 (возможно, с использованием Expressions.numberTemplate())? Или мы вынуждены использовать querydsl-sql?

  2. Если нам нужно использовать 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?

  3. Если мы используем querydsl-sql, есть ли способ повторно использовать наши предложения предикатов/сортировок/объединений querydsl-jpa в запросе querydsl-sql? Или нам нужно дублировать этот код, используя классы, специфичные для querydsl-sql?

  4. Я также рассматриваю возможность создания функции базы данных, которая делегирует TIMESTAMPDIFF(SECOND, x, y), но она не очень переносима...

  5. Я что-то упускаю? Есть ли более простой способ сделать то, что я пытаюсь сделать?


person Etienne Neveu    schedule 10.07.2015    source источник


Ответы (1)


Используя выражения шаблона, вы должны иметь возможность вставлять любые пользовательские фрагменты JPQL в запрос Querydsl. Это должно ответить на ваш первый вопрос.

Использование и querydsl-jpa, и querydsl-sql в одном проекте возможно, но добавляет некоторую сложность.

person Timo Westkämper    schedule 21.07.2015