在@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 中使用 HashSet 作为参数会引发 IllegalArgumentException