首页 > 解决方案 > 多个参数同时搜索 Criteria Api

问题描述

我有这段代码,它只适用于输入输入字符串的一个单词。但我想进行组合搜索。例如,我想写family和name,我想和同时拥有这个名字和family的人有结果。

 @Override
    public List<Teacher> searchByString(String str) {

        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
        CriteriaQuery<Teacher> criteriaQuery = criteriaBuilder.createQuery(Teacher.class);
        Root<Teacher> TeacherRoot = criteriaQuery.from(Teacher.class);

        Predicate predicateForName
                = criteriaBuilder.like(criteriaBuilder.lower(TeacherRoot.get("name")), "%" + str.toLowerCase() + "%");

        Predicate predicateForFam
                = criteriaBuilder.like(criteriaBuilder.lower(TeacherRoot.get("fam")), "%" + str.toLowerCase() + "%");

        Predicate predicateForOtch
                = criteriaBuilder.like(criteriaBuilder.lower(TeacherRoot.get("otch")), "%" + str.toLowerCase() + "%");

        Predicate predicateForPhone
                = criteriaBuilder.like(TeacherRoot.get("phoneNumber"), "%" + str + "%");

        Predicate predicateForDate
                = criteriaBuilder.like(TeacherRoot.get("dateOfBirth").as(String.class), "%" + str + "%");

        Predicate predicateFinal = criteriaBuilder.or(
                predicateForName,
                predicateForFam,
                predicateForOtch,
                predicateForPhone,
                predicateForDate);

        criteriaQuery.where(predicateFinal);

        return em.createQuery(criteriaQuery).getResultList();

    }

样本数据:

1   John Newman      London      8-999990999
2   John Malkovich   Paris    8-999995999
3   John NewMan      Moscow      8-999995999

输入字符串:约翰纽曼

结果记录:

1   John Newman   London   8-999990999
3   John NewMan   Moscow   8-999995999

输入字符串:John 5(姓名为 John 且电话号码为 5 的记录)

结果记录:

2   John Malkovich   Paris    8-999995999
3   John NewMan      Moscow   8-999995999

查询的组合可以不同。

标签: hibernatejpasearchdaocriteria-api

解决方案


输入字符串 = John 5(姓名为 John 且电话号码为 5 的记录)

这里使用您输入的谓词如下所示:

        Predicate predicateForName = criteriaBuilder.like(
             criteriaBuilder.lower(TeacherRoot.get("name")), 
             "%john 5%");

        //other predicates

        Predicate predicateForPhone = criteriaBuilder.like(
              TeacherRoot.get("phoneNumber"),
              "%John 5%");

您尝试在name like "%john 5%"和中查找记录phoneNumber like "%John 5%"

您必须将输入字符串拆分为单词并为每个单词使用谓词。

public List<Teacher> searchByString(String str) {

        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
        CriteriaQuery<Teacher> criteriaQuery = criteriaBuilder.createQuery(Teacher.class);
        Root<Teacher> TeacherRoot = criteriaQuery.from(Teacher.class);

        Predicate predicateFinal = getPredicateByInput(str, criteriaBuilder);

        criteriaQuery.where(predicateFinal);

        return em.createQuery(criteriaQuery).getResultList();

}

public Predicate getPredicateByInput(String input, CriteriaBuilder criteriaBuilder) {
        String[] words = input.split(" ");

        Predicate predicate = null;
        for(String word : words) {
          Predicate wordPredicate = getPredicateByWord(word, criteriaBuilder);

          if(predicate == null) 
              predicate = wordPredicate;
          else
              predicate = criteriaBuilder.or(predicate, wordPredicate);
        }

        Objects.requireNonNull(predicate, "Null predicate is not allowed. Invalid input string '" + input + "'");

        return predicate;
}

private Predicate getPredicateByWord(String word, CriteriaBuilder criteriaBuilder) {

    Predicate predicateForName = criteriaBuilder.like(
                      criteriaBuilder.lower(TeacherRoot.get("name")), 
                      "%" + word.toLowerCase() + "%");

    Predicate predicateForFam = criteriaBuilder.like(
                      criteriaBuilder.lower(TeacherRoot.get("fam")), 
                      "%" + word.toLowerCase() + "%");

    Predicate predicateForOtch = criteriaBuilder.like(
                      criteriaBuilder.lower(TeacherRoot.get("otch")), 
                      "%" + word.toLowerCase() + "%");

    Predicate predicateForPhone = criteriaBuilder.like(
                     TeacherRoot.get("phoneNumber"), 
                     "%" + word + "%");

    Predicate predicateForDate = criteriaBuilder.like(
                     TeacherRoot.get("dateOfBirth").as(String.class), 
                     "%" + word + "%");

    return criteriaBuilder.or(
                        predicateForName,
                        predicateForFam,
                        predicateForOtch,
                        predicateForPhone,
                        predicateForDate);
}

Like 子句是重量级的,所以你应该尽量避免多余的谓词


推荐阅读