设置@NamedQuery中为null的参数(JPA QL 1.0)

时间:2011-06-02 11:50:00

标签: java jpa jpql

我正在编写一个用于搜索文档的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查询以处理空值?

2 个答案:

答案 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。