我正在编写一个用于搜索文档的JPA QL命名查询。这应该只在一个查询中完成,我不能切换到本机SQL(这是非功能性要求)。 我写的查询如下:
query = "select doc from Doc doc " +
" join doc.Csts cst " +
" where cst.cstFrstNm like :FrstNm " +
" and cst.cstLastNm like :LastNm " +
" and doc.resId = :id ";
使用以下说明对此查询进行参数化:
query.setParameter("FrstNm ", firstName + '%');
query.setParameter("LastNm ", lastName + '%');
query.setParameter("id", resId);
上面代码中的 firstName, lastName, resId
是我的搜索条件,它们都是字符串,它们可以为空。当其中一个为null时,在调用查询时不应将其考虑在内。
例如:
假设:firstName =“John”,lastName =“Doe”且resId为null,那么查询应返回Doc表中用于John Doe的所有条目,无论它们是什么样的resId。
我试图将额外的OR和AND条件放入查询中,以检查resId是否为null但它不起作用。我在HSQLDB上测试它。
是否可以通过任何方式修改此JPA查询以处理空值?
答案 0 :(得分:3)
两种解决方案:
首先,不要使用命名查询并为每个请求创建一个新查询:
boolean first = true;
query = query = "select doc from Doc doc " +
" join doc.Csts cst " +
if (firstName != null) {
query += (first ? " where " : " and ");
query += " cst.cstFrstNm like :FrstNm ";
first = false;
}
query += ";";
// ...
第二个解决方案,您正在使用通配符。如果您的参数为空,只需在查询中添加'%',它将匹配所有相应的字符串:
query.setParameter("FrstNm ", (firstName != null ? firstName : "") + '%');
query.setParameter("LastNm ", (lastName != null ? lastName : "") + '%');
如果firstName为空,则查询将如下所示:
... cst.cstFrstNm like '%' ...
并将匹配所有值。这将导致参数不过滤任何结果,其行为类似于不存在的行为。
答案 1 :(得分:1)
您可能需要动态构建查询以满足您的参数。例如:
public List<Employee> findEmployees(String name, String deptName, String projectName, String city) {
StringBuffer query = new StringBuffer();
query.append("SELECT DISTINCT e ");
query.append("FROM Employee e LEFT JOIN e.projects p ");
query.append("WHERE ");
List<String> criteria = new ArrayList<String>();
if (name != null) { criteria.add("e.name = :name"); }
if (deptName != null) { criteria.add("e.dept.name = :dept"); }
if (projectName != null) { criteria.add("p.name = :project"); }
if (city != null) { criteria.add("e.address.city = :city"); }
if (criteria.size() == 0) {
throw new RuntimeException("no criteria");
}
for (int i = 0; i < criteria.size(); i++) {
if (i > 0) { query.append(" AND "); }
query.append(criteria.get(i));
}
Query q = em.createQuery(query.toString());
if (name != null) { q.setParameter("name", name); }
if (deptName != null) { q.setParameter("dept", deptName); }
if (projectName != null) { q.setParameter("project", projectName); }
if (city != null) { q.setParameter("city", city); }
return (List<Employee>)q.getResultList();
}
如果您使用JPA 2.0进行此类任务,您也会考虑使用Criteria API。