5

さまざまな理由から、Criteria API に頼らずに部分的に動的な HQL クエリを作成しようとしています。HQL 式を使用して where 制限を回避する簡単な方法があるかどうかを知りたかったのです。たとえば、正常に動作する元のクエリは次のとおりです。

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE profile.status IN :statusCodes
AND   profile.orgId IN :orgIds

StatusCodes は文字列のリストで、orgIds は整数のリストです。ただし、どちらもオプションであり、コレクションの代わりに null が渡された場合は制限しないでください。私はこれを次のように達成しようとしました:

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE (:statusCodes IS NULL OR profile.status IN :statusCodes)
AND   (:orgIds IS NULL OR profile.orgId IN :orgIds)

残念ながらこれは機能しませんでしたが、別の式を使用するか、デフォルト値を渡すことで、機能する可能性のある他のアプローチはありますか?

編集:明確にするために、クエリを動的に構築するのではなく、NamedQueryを使用する方法を探しています。

解決策: 追加のクエリ パラメータを使用してそれを実現しました。2 つのヘルパー メソッドを作成しました。

private void setRequiredParameter(TypedQuery<?> query, String name, Object value) {
    query.setParameter(name, value);
}

private void setOptionalParameter(TypedQuery<?> query, String name, Object value) {
    query.setParameter(name, value);
    query.setParameter(name + "Optional", value == null ? 1 : 0);
}

そして、次のようなクエリ:

SELECT customer 
        FROM Customer as customer 
        INNER JOIN  customer.profile as profile 
        WHERE (:statusCodesOptional = 1 OR profile.status IN :statusCodes)
        AND (:orgIdsOptional = 1 OR profile.orgId  IN :orgIds)
4

3 に答える 3

7

私の提案は、マップから値を取得するクエリに必要なすべてのパラメータを実行前に設定した後、マップにすべてのパラメータを配置し、動的なクエリを構築することです。

Map<String, Object> pars = new HashMap<String,Object>();
pars.put("statusCodes", statusCodes);
pars.put("orgIds", orgIds);

StringBuilder b = "SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1";
if (statusCodes != null) {
  b.append(" and profile.status in :statusCodes");
}
if (orgIds != null) {
  b.append(" and profile.orgId in :statusCodes");
}

...

Query q = session.createQuery(b.toString());

...

for (String p : q.getNamedParameters()) {
  q.setParameter(p, pars.get(p));
}

もちろん、いくつかの改善が必要です。たとえば、パラメーターが設定されていないときに例外をスローしたり、複雑さがいくつかの単純なパラメーターよりも大きい場合は型付きパラメーターを使用したりします。

于 2012-05-17T18:23:10.513 に答える
2

動的クエリを絶対に回避する必要がある場合は、2 つの追加パラメーターを犠牲にして回避できます。

SELECT customer 
  FROM Customer AS customer 
  JOIN customer.profile AS profile 
 WHERE (profile.status IN :statusCodes OR :statusCodeCount = 0)
   AND (profile.orgId IN :orgIds OR :orgIdCount = 0)

Java コードでは、次のようにします。

session.getNamedQuery("your.query.name")
       .setParameterList("statusCodes", statusCodes)
       .setParameter("statusCodeCount", statusCodes.length)
       .setParameterList("orgIds", orgIds)
       .setParameter("orgIdCount", orgIds.length);

シナリオを処理する場合は、配列が長さ 0 であることを確認するnullか、追加の if チェックを指定する必要があります。null

そうは言っても、HQL は明確に定義された (静的な) クエリに適しています。動的パラメーターを回避することはできますが、動的ソートを回避することはできません。

于 2012-05-17T18:31:56.137 に答える
1

クエリを動的に生成する必要があります。

StringBuilder hql = 
    new StringBuilder("SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1")
if (statusCodes != null) {
    hql.append(" and profile.status IN :statusCodes");
}
if (orgIds != null) {
    hql.append(" and profile.orgId IN :orgIds");
}

もちろん、パラメーターが null でない場合にのみ、パラメーターをクエリに設定する必要もあります。

于 2012-05-17T18:11:18.763 に答える