【问题标题】:set parameter which is null in @NamedQuery (JPA QL 1.0)在@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 查询来处理空值?

【问题讨论】:

    标签: java jpa jpql


    【解决方案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。
    猜你喜欢
    • 1970-01-01
    • 2016-04-02
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多