Родные запросы JPA/Hibernate не распознают параметры
Я использую Hibernate/JPA для выполнения собственных запросов PostGIS. Проблема с этими запросами заключается в том, что им нужны параметры, которые не относятся к классической форме X = 'value.
Например, следующие строки сбой
String queryString = "select * from Cell c where ST_DWithin(c.shape, SetSRID(ST_GeomFromEWKT('POINT(:lon :lat)'),4326), 0.1)";
Query query = Cell.em().createNativeQuery(queryString, Cell.class);
query.setParameter("lon", longitude);
query.setParameter("lat", latitude);
play.exceptions.JavaExecutionException: org.hibernate.QueryParameterException: could not locate named parameter [lon]
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:259)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryParameterException: could not locate named parameter [lon]
at org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:358)
Однако следующий запрос работает:
String queryString = String.format("select * from Cell c where ST_DWithin(c.shape, SetSRID(ST_GeomFromEWKT('POINT(%f %f)'),4326), 0.1)", longitude, latitude);
Query query = Cell.em().createNativeQuery(queryString, Cell.class);
(но он подвержен SQL-инъекциям...)
Кто-нибудь знает, как использовать setParameter()
в этом случае?
Ответы
Ответ 1
Использование именованных параметров не определено для собственных запросов. Из спецификации JPA (раздел 3.6.3 Именованные параметры):
Именованные параметры соответствуют правилам для идентификаторы, определенные в разделе 4.4.1. Использование именованных параметров применяется к язык запросов Java Persistence, и не определяется для собственных запросов. Только привязка позиционных параметров может быть портативно используемым для собственных запросов.
Итак, попробуйте следующее:
String queryString = "select * from Cell c where ST_DWithin(c.shape, SetSRID(ST_GeomFromEWKT('POINT(?1 ?2)'),4326), 0.1)";
Query query = Cell.em().createNativeQuery(queryString, Cell.class);
query.setParameter(1, longitude);
query.setParameter(2, latitude);
Обратите внимание, что в JPA >= 2.0 вы можете использовать именованные параметры в собственных запросах.
Ответ 2
Возможно, вы можете заменить
'POINT(:lon :lat)'
с
'POINT(' || :lon || ' ' || :lat || ')'
Таким образом, параметры находятся за пределами константных строк и должны распознаваться парсером запросов.
Ответ 3
У меня была аналогичная проблема, и я обнаружил, что параметры могут быть заданы с вопросительными знаками в собственных запросах.
Попробуйте следующее:
String queryString = "select * from Cell c where ST_DWithin(c.shape, SetSRID(ST_GeomFromEWKT('POINT(? ?)'),4326), 0.1)";
Query query = Cell.em().createNativeQuery(queryString, Cell.class);
query.setParameter(1, longitude);
query.setParameter(2, latitude);
Ответ 4
Итак, идея заключалась в использовании трюка конкатенации, предложенного Йорном Хорстманом, чтобы заставить postgres распознавать параметры.
Работает следующий код:
String queryString = "select * from Cell c where ST_DWithin(c.shape, SetSRID(ST_GeomFromEWKT('POINT(' || :lon || ' ' || :lat || ')'),4326), 0.2)";
Query query = Cell.em().createNativeQuery(queryString, Cell.class);
query.setParameter("lon", longitude);
query.setParameter("lat", latitude);
Большое спасибо за ваши ответы!
Ответ 5
Вы также можете избавиться от всего
ST_GeomFromEWKT('POINT(' || :lon || ' ' || :lat || ')')
вызовите и замените его
ST_Point(:lon,:lat)
Тогда вам не нужно беспокоиться о котировках.
Ответ 6
Ответ на Pascal правильный, но... Как ваше решение SQL-инъекции подвержено?
Если вы используете String.format
и тип parmater %f
в своем примере, то ничего, кроме числа, вызывает java.util.IllegalFormatConversionException. Нет значения пропускной способности, например "xxx" ИЛИ 1 = 1 - ".
Будьте осторожны, используя %s
в String.format
, SQL-версия готова.
Ответ 7
Я столкнулся с подобной проблемой. Я использовал собственный запрос в репозитории с? 1. Он разрешил его, окружая параметр вокруг скобок следующим образом.
SELECT * FROM XYZ WHERE ABC = (?1)
http://javageneralist.blogspot.com/2011/06/jpa-style-positional-param-was-not.html