使用HQL表达,而不是标准动态HQL查询?(Dynamic HQL query using hql

2019-07-29 10:30发布

我试图写一个部分动态的HQL查询,而无需诉诸标准API因各种原因。 我想知道如果在那里使用HQLs表达的限制有一个简单的方法来短路。 例如,这里是工作正常原始查询:

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,不能动态地构建以任何方式查询。

解决办法:我使用了额外的查询参数来完成它。 我创建了两个辅助方法:

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)

Answer 1:

如果你绝对必须避免动态查询,你可以在两个额外的参数为代价这样做:

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

你需要确保数组是零长度,而不是null或供应额外如果检查处理null的场景。

所有这一切说,HQL真的更适合定义明确的(如静)查询。 您可以解决动态参数,你将不能够解决动态排序。



Answer 2:

我的建议是把所有的参数在地图并建立动态查询,构建执行前设置由查询从地图取值所需的所有参数后:

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

当然,还需要例如抛出异常的一些改进时,未设置参数,使用类型的参数,如果复杂度比几个简单的参数等等大。



Answer 3:

你必须动态生成的查询:

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

当然,你也必须将参数设置为查询只如果他们不为空。



文章来源: Dynamic HQL query using hql expressions rather than Criteria?