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 ?
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.
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.
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);
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 !
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.
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 %s
String.format
est-SQL injection de prêt.
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