简体   繁体   English

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

[英]JPA/Hibernate Native Queries do not recognize Parameters

I am using Hibernate/JPA to execute native PostGIS queries.我正在使用 Hibernate/JPA 来执行本机 PostGIS 查询。 The problem with these queries is that they need parameters that are not of the classical X = 'value' form.这些查询的问题在于它们需要不是经典 X = 'value' 形式的参数。

For example, the following lines crash例如,以下几行崩溃

 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)

The following query works however :但是,以下查询有效:

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

(but it is SQL-injection-prone...) (但它是 SQL 注入倾向的......)

Does anyone know how to use setParameter() in this case ?有谁知道在这种情况下如何使用setParameter()吗?

The use of named parameters is not defined for native queries.本机查询未定义命名参数的使用。 From the JPA specification (section 3.6.3 Named Parameters ):来自 JPA 规范(第3.6.3命名参数):

Named parameters follow the rules for identifiers defined in Section 4.4.1.命名参数遵循第 4.4.1 节中定义的标识符规则。 The use of named parameters applies to the Java Persistence query language, and is not defined for native queries.命名参数的使用适用于 Java Persistence 查询语言,并没有为本地查询定义。 Only positional parameter binding may be portably used for native queries .只有位置参数绑定可以可移植地用于本机查询

So try the following instead:因此,请尝试以下操作:

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

Note that in JPA >= 2.0 you can use named parameters in native queries.请注意,在 JPA >= 2.0 中,您可以在本机查询中使用命名参数。

Maybe you can replace也许你可以更换

'POINT(:lon :lat)'

with

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

This way the parameters are outside of constant strings and should be recognized by the query parser.这样参数就在常量字符串之外,应该被查询解析​​器识别。

I had a similar problem and found that parameters can be set with question marks in native queries.我有一个类似的问题,发现在本机查询中可以用问号设置参数。 Try this:尝试这个:

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

You can also get rid of the whole你也可以摆脱整个

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

call and replace it with调用并将其替换为

ST_Point(:lon,:lat)

Then you don't have to worry about quotes.那么你不必担心报价。

Pascal's answer is correct, but... How is your solution SQL injection prone? Pascal 的回答是正确的,但是……您的解决方案如何容易发生 SQL 注入? If you're using String.format and parmater type %f in your example then anything else than number throws java.util.IllegalFormatConversionException.如果您在示例中使用String.format和参数类型%f ,那么除数字之外的任何其他内容都会引发 java.util.IllegalFormatConversionException。 There is no possibililty pass value like "xxx' OR 1=1 --".没有像“xxx' OR 1=1 --”这样的可能传递值。

Be careful, using %s in String.format is SQL injection ready.请注意,在String.format使用%s已准备好 SQL 注入。

I faced similar issue.我遇到了类似的问题。 I was using native query in the repository with ?1.我在存储库中使用 ?1 的本机查询。 It resolved it by surrounding the parameter around brackets like the following.它通过将参数括在括号中来解决它,如下所示。

SELECT * FROM XYZ WHERE ABC = (?1)

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

So, the idea was to use the concatenation trick suggested by Jörn Horstmann to force postgres to recognize the parameters.所以,这个想法是使用 Jörn Horstmann 建议的连接技巧来强制 postgres 识别参数。 The following code works :以下代码有效:

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

Thanks a lot for your answers !非常感谢你的回答 !

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM