JPA / Hibernate本机查询无法识别参数

时间:2010-06-29 19:55:45

标签: java hibernate orm jpa postgis

我正在使用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 个答案:

答案 0 :(得分:81)

未为本机查询定义命名参数的使用。从JPA规范( 3.6.3命名参数部分):

  

命名参数遵循规则   第4.4.1节中定义的标识符。   命名参数的使用适用于   Java持久性查询语言,   并且没有为本机查询定义。   只有位置参数绑定可能   可以移植用于本机查询

请尝试以下方法:

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中,可以在原生查询中使用命名参数。

答案 1 :(得分:17)

也许你可以替换

'POINT(:lon :lat)'

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

这样,参数不在常量字符串之内,应该由查询解析器识别。

答案 2 :(得分:4)

我遇到了类似的问题,发现可以在本机查询中使用问号设置参数。 试试这个:

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);

答案 3 :(得分:2)

因此,我们的想法是使用JörnHorstmann建议的连接技巧来强制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);

非常感谢您的回答!

答案 4 :(得分:2)

你也可以摆脱整个

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

调用并替换为

ST_Point(:lon,:lat)

然后你不必担心报价。

答案 5 :(得分:2)

Pascal的回答是正确的,但是......你的解决方案SQL注入是怎样的? 如果您在示例中使用String.format和parmater类型%f,那么除了数字之外的任何内容都会抛出java.util.IllegalFormatConversionException。没有可能的传递值,如" xxx'或1 = 1 - "。

请注意,%s中的String.format是SQL注入就绪。

答案 6 :(得分:2)

我遇到了类似的问题。我在存储库中使用本机查询?1。它通过围绕括号括起来解决它,如下所示。

SELECT * FROM XYZ WHERE ABC = (?1)

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