49

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()この場合の使い方を知っている人はいますか?

4

7 に答える 7

83

名前付きパラメーターの使用は、ネイティブ クエリでは定義されていません。JPA 仕様から (セクション3.6.3 Named Parameters ):

名前付きパラメーターは、セクション 4.4.1 で定義されている識別子の規則に従います。名前付きパラメーターの使用は、Java Persistence クエリ言語に適用され、ネイティブ クエリでは定義されていません。 ネイティブ クエリに移植可能に使用できるのは、位置パラメータ バインディングのみです

そのため、代わりに次のことを試してください。

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 では、名前付きパラメーターをネイティブ クエリで使用できることに注意してください。

于 2010-06-29T22:35:17.310 に答える
19

多分あなたは置き換えることができます

'POINT(:lon :lat)'

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

このように、パラメーターは定数文字列の外側にあり、クエリパーサーによって認識される必要があります。

于 2010-06-29T20:50:10.947 に答える
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);
于 2014-02-26T21:38:44.807 に答える
2

全体を取り除くこともできます

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

を呼び出して置き換えます

ST_Point(:lon,:lat)

その後、引用符について心配する必要はありません。

于 2012-12-05T16:27:30.073 に答える
2

そこで、Jörn Horstmann によって提案された連結トリックを使用して、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);

ご回答ありがとうございます。

于 2010-06-30T12:50:26.880 に答える
2

Pascal の答えは正しいですが... SQL インジェクションが発生しやすいソリューションはどのようになっていますか? String.format例でパラメーター タイプを使用している場合%f、数値以外は java.util.IllegalFormatConversionException をスローします。「xxx' OR 1=1 --」のようなパス値はありません。

%sin を使用するString.formatと、SQL インジェクションの準備ができていることに注意してください。

于 2013-02-26T17:47:30.607 に答える