#java #sql #postgresql #hibernate #jpql
Вопрос:
Я использую PostgreSQL 9.6
с Hibernate 5.4.8
, Java 8
и пружинный каркас. Мне нужно вызвать функцию postgres
CREATE OR REPLACE FUNCTION function_that_return_array(givenIds character varying(255)) RETURNS int[] AS
'
BEGIN
RETURN string_to_array($1,'','');
END
' LANGUAGE plpgsql;
в рамках JPQL-запроса
private static final String JPQL_QUERY =
" SELECT NEW com.package.CustomProjection( "
" e.id, "
" e.value "
" ) "
" FROM SomeEntity e "
" WHERE e.id = ANY(function_that_return_array(:ids))";
и использование entity manager:
@Autowired
private final EntityManager entityManager;
// ...
this.entityManager.createQuery(JPQL_QUERY, CustomProjection.class)
.setParameter("ids", "1,2,3")
.getResultList();
и это приводит к следующему исключению:
antlr.NoViableAltException: unexpected token: function_that_return_array
at org.hibernate.hql.internal.antlr.HqlBaseParser.selectFrom(HqlBaseParser.java:1055) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.queryRule(HqlBaseParser.java:748) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.subQuery(HqlBaseParser.java:3910) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.quantifiedExpression(HqlBaseParser.java:3515) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.unaryExpression(HqlBaseParser.java:3373) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
...
antlr.MismatchedTokenException: expecting EOF, found ')'
at antlr.Parser.match(Parser.java:211) ~[antlr-2.7.7.jar:?]
at org.hibernate.hql.internal.antlr.HqlBaseParser.statement(HqlBaseParser.java:215) [hibernate-core-5.4.8.Final.jar:5.4.8.Final]
Приведенный выше пример очень упрощен, но он правильно представляет производственную проблему. Когда я вызываю функцию выше в собственном SQL, она отлично работает:
select *
from some_entity e
where e.id = ANY(function_that_return_array('1,2,3,4'))
Кто-нибудь знает, как вызвать функцию postgres в JPQL и перейти в спящий режим, или может указать мне, что я делаю неправильно? Я читал много статей, подобных этой, поэтому задавал вопросы и пробовал десятки комбинаций, но пока безуспешно. Заранее спасибо.
Ответ №1:
На диалекте гибернации вы не можете напрямую вызывать незарегистрированные пользовательские функции базы данных. Исключение в clear, hibernate ничего не знает о вашей функции:
unexpected token: function_that_return_array
Здесь у вас есть два варианта:
- Вызовите свою функцию с помощью универсального механизма для пользовательских функций:
использовать
function('function_that_return_array', '1,2,3,4')
вместо
function_that_return_array('1,2,3,4')
- Второй вариант-зарегистрировать свою функцию:
https://docs.jboss.org/hibernate/orm/5.1/javadocs/org/hibernate/dialect/Dialect.html#registerFunction-java.lang.Строка-org.спящий режим.диалект.функция.Функция SQLFunction-
Пример:
public class MyDialect extends PostgreSQLXXDialect {
public MyDialect() {
super();
registerFunction("function_that_return_array", new StandardSQLFunction("function_that_return_array"));
}
}
Комментарии:
1. Спасибо, к сожалению, при использовании универсального механизма он выдает то же исключение с сообщением
unexpected token: function
. Я также попробовал второй подход с регистрацией диалекта. Точка останова была запущена внутри конструктора, так что моя функция postgres действительно была зарегистрирована. Кроме того, я вызвал статическийgetFunctions()
метод, и он правильно вернул нашу функцию postgres. Но это все равно вызывает то же исключение. Может быть, это вопрос версии библиотеки или какой-то отсутствующей зависимости?2. Или, может быть, это из-за вызова функции внутри
ANY
оператора? Или также требуются какие-то специальные расценки?3. function_that_return_array возвращает массив целых чисел, поэтому вы можете просто использовать оператор IN ( … ), это эквивалент для «ЛЮБОГО».
4. когда я использую
IN
оператор, он выдает следующую ошибку:SQL Error [42883]: ERROR: operator does not exist: integer = integer[]
. Я пытался использоватьTABLE
тип возврата вместоARRAY
, но спящий режим также не удается. Я перепробовал десятки комбинаций, но по какой-то причине hibernate не может преобразовать JPQL в собственный SQL. Это все равно бросаетunexpected token
илиunexpected end of subtree
зависит от подхода, который я пытаюсь. Для сравнения, когда я использую собственный запрос через тот же менеджер сущностей, он работает правильно.5.
ANY
это специальный квантор в HQL, поэтому вы не можете использовать его таким образом. Вам придется упаковатьANY
его в функцию, которую вы регистрируете.