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

我试图编写一个部分动态的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) 

如果绝对必须避免动态查询,则可以牺牲两个附加参数来实现:

 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更适合于定义明确的(例如静态)查询。 您可以解决动态参数,您将无法解决动态排序问题。

我的建议是将所有参数放在一个映射中并构建动态查询,在执行之前构建之后设置查询所需的所有参数从地图中获取值:

 Map pars = new HashMap(); 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)); } 

当然,在未设置参数时,例如抛出exception需要一些改进,如果复杂性大于几个简单参数,则使用类型参数等等。

您必须动态生成查询:

 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时,您还必须将参数设置为查询。