Собственные запросы JPA / Hibernate не распознают параметры - PullRequest
45 голосов
/ 29 июня 2010

Я использую 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() в этом случае?

Ответы [ 7 ]

81 голосов
/ 30 июня 2010

Использование именованных параметров не определено для собственных запросов. Из спецификации 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 вы можете использовать именованные параметры в собственных запросах.

17 голосов
/ 30 июня 2010

Возможно, вы можете заменить

'POINT(:lon :lat)'

на

'POINT(' || :lon || ' ' || :lat || ')'

Таким образом, параметры находятся за пределами константных строк и должны распознаваться синтаксическим анализатором запросов.

4 голосов
/ 27 февраля 2014

У меня была похожая проблема, и я обнаружил, что параметры могут быть заданы с вопросительными знаками в собственных запросах.Попробуйте это:

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);
2 голосов
/ 16 марта 2015

Я столкнулся с подобной проблемой. Я использовал собственный запрос в хранилище с? 1. Он решил эту проблему, заключив параметр в квадратные скобки, как показано ниже.

SELECT * FROM XYZ WHERE ABC = (?1)

http://javageneralist.blogspot.com/2011/06/jpa-style-positional-param-was-not.html

2 голосов
/ 26 февраля 2013

Ответ Паскаля верен, но ... Как ваше решение подвержено внедрению SQL-кода?Если вы используете String.format и тип parmater %f в своем примере, тогда все, кроме числа, создает java.util.IllegalFormatConversionException.Нет никакого возможного проходного значения, такого как «xxx» ИЛИ 1 = 1 - ».

Будьте осторожны, использование %s в String.format готово к внедрению SQL.

2 голосов
/ 05 декабря 2012

Вы также можете избавиться от всего вызова

ST_GeomFromEWKT('POINT(' || :lon || ' ' || :lat || ')')

и заменить его на

ST_Point(:lon,:lat)

Тогда вам не нужно беспокоиться о кавычках.

2 голосов
/ 30 июня 2010

Итак, идея состояла в том, чтобы использовать трюк конкатенации, предложенный Йорном Хорстманном, чтобы заставить 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);

Большое спасибо за ваши ответы!

...