我正在使用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()
?
答案 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