小编典典

使用hql表达式而不是Criteria进行动态HQL查询?

hibernate

由于各种原因,我试图编写部分动态的HQL查询而不使用Criteria
API。我想知道是否有一种简单的方法可以使用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的方法,而不是以任何方式动态构建查询。

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

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)

阅读 258

收藏
2020-06-20

共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实际上更适合定义明确(例如静态)的查询。您可以解决动态参数,而不能解决动态排序。

2020-06-20