我试图写一个部分动态的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)
如果你绝对必须避免动态查询,你可以在两个额外的参数为代价这样做:
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<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));
}
当然,还需要例如抛出异常的一些改进时,未设置参数,使用类型的参数,如果复杂度比几个简单的参数等等大。
你必须动态生成的查询:
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");
}
当然,你也必须将参数设置为查询只如果他们不为空。