Les requêtes natives JPA / Hibernate ne reconnaissent pas les paramètres

J'utilise Hibernate/JPA pour exécuter des requêtes PostGIS natives. Le problème avec ces requêtes est qu'ils ont besoin de paramètres qui ne sont pas de la classique X = 'valeur'.

Par exemple, les lignes suivantes 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)

La requête suivante fonctionne cependant :

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

(mais elle est sujette à L'injection SQL...)

quelqu'un sait-il comment utiliser setParameter() dans ce cas ?

42
demandé sur Pascal Thivent 2010-06-29 23:55:44

7 réponses

utilisation des paramètres nommés n'est pas défini pour les requêtes. De la spécification JPA (section 3.6.3 Paramètres Nommés):

les paramètres nommés suivent les règles pour identificateurs définis à la Section 4.4.1. L'utilisation des paramètres nommés s'applique le langage de requête Java Persistence, et n'est pas défini pour les requêtes. seulement la liaison des paramètres de position peut être utilisé de façon appropriée pour les les requêtes.

alors essayez ce qui suit à la place:

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

notez que dans JPA >= 2.0 vous pouvez utiliser paramètres nommés dans les requêtes natives.

78
répondu Pascal Thivent 2015-08-26 09:46:18

peut-être Pouvez-vous remplacer

'POINT(:lon :lat)'

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

de cette façon les paramètres sont en dehors des chaînes constantes et doivent être reconnus par l'analyseur de requête.

17
répondu Jörn Horstmann 2012-08-15 15:29:39

j'ai eu un problème similaire et j'ai trouvé que les paramètres peuvent être définis avec des points d'interrogation dans les requêtes natives. Essayez ceci:

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
répondu Ferenc 2014-02-26 21:38:44

donc, l'idée était d'utiliser le truc de concaténation suggéré par Jörn Horstmann pour forcer postgres à reconnaître les paramètres. Le code suivant fonctionne :

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

Merci beaucoup pour vos réponses !

2
répondu user99054 2010-06-30 12:50:26

vous pouvez aussi vous débarrasser de l'ensemble

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

appel et de le remplacer par

ST_Point(:lon,:lat)

alors vous n'avez pas à vous soucier des citations.

2
répondu MDAHatter 2012-12-05 16:51:26

la réponse de Pascal est correcte, mais... Comment votre solution SQL est-elle sujette à l'injection? Si vous utilisez String.format et de type parmater %f dans votre exemple, alors n'importe quoi d'autre que le nombre jette java.util.IllegalFormatConversionException. Il n'y a pas de valeur de passe possible comme "xxx "ou 1=1--".

attention, à l'aide de %sString.format est-SQL injection de prêt.

2
répondu Boris Šuška 2013-02-26 17:47:30

j'ai fait face à des questions semblables. J'utilisais la requête native dans le dépôt avec ?1. Il l'a résolu en entourant le paramètre autour des parenthèses comme suit.

SELECT * FROM XYZ WHERE ABC = (?1)

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

2
répondu yousafsajjad 2015-03-16 20:44:01