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

Posted

技术标签:

【中文标题】在@NamedQuery (JPA QL 1.0) 中设置为空的参数【英文标题】:set parameter which is null in @NamedQuery (JPA QL 1.0) 【发布时间】:2011-06-02 11:50:00 【问题描述】:

我正在编写一个用于搜索文档的 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 是我的搜索条件,它们都是字符串,可以为空。当其中之一为空时,调用查询时不应考虑它。

例如:

假设:firstName = "John", lastName = "Doe" 并且 resId 为空,那么查询应该返回 Doc 表中所有用于用户 John Doe 的条目,无论他们的 resId 是什么。

我试图将额外的 OR 和 AND 条件放入查询中,以检查 resId 是否为空,但它不起作用。我正在 HSQLDB 上测试它。

有没有办法修改这个 JPA 查询来处理空值?

【问题讨论】:

【参考方案1】:

两种解决方案:

第一个,不要使用命名查询并为每个请求制作一个新查询:

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 '%' ...

并且会匹配所有的值。这将导致参数不过滤任何结果,其行为类似于不存在。

【讨论】:

非常感谢!实际上我已经考虑过这些解决方法,但我希望有一些额外的方法。但似乎没有 JPA2.0 就可以做到这一点。 doc.resId = :resId | 问题未解决是否可以将 e '%' 也用于 = 或 in ??【参考方案2】:

您可能需要动态构建查询以满足您的参数。例如:

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。

【讨论】:

@edolorzo:谢谢,有人告诉我使用@NamedQuery,所以这个解决方法没有帮助,我不能使用 JPA 2.0。

以上是关于在@NamedQuery (JPA QL 1.0) 中设置为空的参数的主要内容,如果未能解决你的问题,请参考以下文章

为啥元字符 * 不能在 JPA 的实体中的 NamedQuery 中使用?

JPA 计数 NamedQuery

在 JPA NamedQuery 中使用 HashSet 作为参数会引发 IllegalArgumentException

从 JPA 实体的接口中检索 @NamedQuery

JPA:如何将@NamedStoredProcedureQuery 与@NamedQuery 结合起来执行周边搜索?

EclipseLink JPA NamedQuery 在 Set 类型的字段中找不到 .size 属性