46 votes

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'elles ont besoin de paramètres qui ne sont pas de la forme classique X = 'valeur'.

Par exemple, les lignes suivantes plantent

  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 c'est sujet à l'injection SQL ...)

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

81voto

Pascal Thivent Points 295221

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

Les paramètres nommés suivre les règles de la les identificateurs définis dans la Section 4.4.1. L'utilisation de paramètres nommés s'applique à la Java Persistence query language, et n'est pas défini pour les requêtes. Seulement paramètre de position de liaison peut être de façon portable utilisé pour les requêtes.

Donc, essayez ce qui suit:

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

18voto

Jörn Horstmann Points 18118

Peut-être que vous pouvez remplacer

 'POINT(:lon :lat)'
 

avec

 '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.

4voto

Ferenc Points 33

J'ai eu un problème similaire et j'ai constaté que les paramètres peuvent être définis avec des points d'interrogation dans les requêtes natives. Essaye ça:

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

2voto

MDAHatter Points 11

Vous pouvez également vous débarrasser de l'ensemble

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

appeler et le remplacer par

 ST_Point(:lon,:lat)
 

Ensuite, vous n'avez pas à vous soucier des devis.

2voto

Boris Šuška Points 906

La réponse de Pascal est correcte, mais ... en quoi votre solution est-elle sujette à l'injection SQL? Si vous utilisez String.format et le type de client %f dans votre exemple, toute autre chose que nombre lève java.util.IllegalFormatConversionException. Il n’existe pas de valeur de passage possible telle que "xxx 'OU 1 = 1 -".

Soyez prudent, utiliser %s en String.format est prêt pour l'injection SQL.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X