Поиск по нескольким параметрам одновременно Criteria Api - PullRequest
0 голосов
/ 15 октября 2019

У меня есть этот код, и он работает только для одного слова, вводящего строку ввода. Но я хочу сделать комбинированный поиск. Например, я хочу написать фамилию и имя, и я хочу иметь результаты с людьми, которые имеют это имя и фамилию одновременно.

 @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

Входная строка: Джон 5 (записи с именем Джон и с 5 в телефоне)

Результаты записи:

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

Комбинация запросов может быть различной.

Ответы [ 2 ]

0 голосов
/ 15 октября 2019

Строка ввода = Джон 5 (записи с именем Джон и 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 имеет большой вес, поэтому следует избегать избыточных предикатов

0 голосов
/ 15 октября 2019

Создайте класс searchCriteria с указанными строковыми полями (имя и т. Д.), А затем передайте его в метод searchByString.

Например:

public List<Teacher> searchByString(SearchCriteria criteria)

Внутри метода добавлять только ненулевые предикаты:

if(criteria.name != null) {
   //addPredicate
}
...