【问题标题】:Case insensitive search with Predicate and Criteria API使用 Predicate 和 Criteria API 进行不区分大小写的搜索
【发布时间】:2018-02-26 18:04:35
【问题描述】:

我目前已经实现了一个动态查询构建器,如果我的查询条件拼写正确,它可以完美运行。由于情况可能并非总是如此,因此我需要一个足够灵活的解决方案来应对条件的任何变化,主要是支持不区分大小写。

当前规范的 toPredicate 方法覆盖代码如下所示:

final List<Predicate> predicates = new ArrayList<Predicate>();

    Path<String> username = root.get("username");
    Path<String> agentCode = root.get("agentCode");
    Path<EntityStatus> status = root.get("status");
    Path<String> firstname = root.get("firstName");
    Path<String> lastname = root.get("lastName");
    Path<String> email = root.get("eMail");


if(criteria.getUsername()!=null && !criteria.getUsername().isEmpty()) {
      predicates.add(cb.equal(username, criteria.getUsername()));
    }

    if(criteria.getAgentCode()!=null && !criteria.getAgentCode().isEmpty()) {
      predicates.add(cb.equal(agentCode, criteria.getAgentCode()));
    }

    if(criteria.getFirstName()!=null && !criteria.getFirstName().isEmpty()) {
      predicates.add(cb.like(firstname, "%"+criteria.getFirstName()+"%"));
    }

    if(criteria.getLastName()!=null && !criteria.getLastName().isEmpty()) {
      predicates.add(cb.equal(lastname, criteria.getLastName()));
    }

    if(criteria.getEMail()!=null && !criteria.getEMail().isEmpty()) {
      predicates.add(cb.equal(email, criteria.getEMail()));
    }

    if(criteria.getStatus()!=null) {
      predicates.add(cb.equal(status, criteria.getStatus()));
    }

    return cb.and(predicates.toArray(new Predicate[predicates.size()]));
  }

从服务层调用的我的存储库接口看起来像这样。

public interface UserRepo extends PagingAndSortingRepository<User, Long> {
     List<User> findAll(Specification spec);
}

【问题讨论】:

  • 采取任何条件变化。”你能更具体地说明允许的变化吗?只是区分大小写吗?顺便说一句,您应该做一个方法来检查并添加是否有效,这确实是重复代码)
  • @AxelH 是的,很抱歉没有指定。它主要必须支持不区分大小写。
  • @JEY 它不是重复的,我已经查看了该帖子,其中解决方案是使用 CriteriaQuery 构建自定义查询。我没有使用我只使用 CriteriaBuilder 并通过接口让 spring JPA 创建和执行查询。我的代码更像是简单地设置条件
  • 完全一样。

标签: java sql spring string jpa


【解决方案1】:

正如@Nikolas Charalambidis 所建议的那样,我使用了他的答案的变体,它适合我的确切实施。 答案只需要修改 predacate.add() 行。 有了这个答案,解决方案就足够灵活,可以支持不区分大小写和部分输入。

predicates.add(cb.like(cb.lower(email), "%"+criteria.getEMail().toLowerCase()+"%"));

【讨论】:

  • 接受Nikolas C 回答然后,您的更新不是关于区分大小写的问题,而是“包含”查询。由于您已经在名字标准中包含了该部分,因此答案中没有必要
  • 如果criteria.getEmail() 不返回文字字符串,则可能还需要在其上使用cb.lower()
  • @JimmyB:在 OP 的情况下,确实如此。那么你的评论有什么意义呢?
  • @NikolasCharalambidis 在问题中我没有看到任何关于 getEmail() 可以返回的类型的内容。
  • @JimmyB:如果 OP 将 toLowerCase() 方法应用于 getEMail() 方法并确认它有效,它显然会返回 String 值。根据这个逻辑,同样的假设是cb 可能不是CriteriaBuilder...是的,我们怎么知道?
【解决方案2】:

通常,您可以使用equalsIgnoreCase() 方法实现不区分大小写。

但是,在这种情况下,您只需解析要比较的值,而无需实现比较本身。因此,您可以使用 toLowerCase() 方法强制以不区分大小写的方式比较所有值。

predicates.add(cb.equal(email.toLowerCase(), criteria.getEMail().toLowerCase()));

编辑:我查看了 CriteriaBuilder 的 JavaEE 文档,发现方法 lower() 可能会有所帮助。

【讨论】:

  • 问题是 email.toLowerCase() 只是方法覆盖上面的一个路径集,不可能在路径上调用它。路径 email = root.get("eMail");
  • Path&lt;T&gt;在你的实现下吗?如果是这样,您的用例是否可以覆盖 getter?
  • 我使用了您的想法,但稍作改动以对应我的实现。我会把它作为答案发布
  • 看起来很棒,很高兴它有帮助:)
猜你喜欢
  • 1970-01-01
  • 2012-06-17
  • 2021-12-18
  • 2012-12-20
  • 2010-09-12
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多