JPA поиск String, Long и Boolean - PullRequest
0 голосов
/ 30 июня 2018

У меня есть приложение Spring-Boot. Есть сущность:

@Entity
@Table(name = "user")
public class User {
    private Long id;
    private String name;
    private Long schoolId;
    private Boolean isActive;
    // getters and setters
}

У меня есть хранилище:

@Repository
public interface UserRepositoryPageable extends PagingAndSortingRepository<User, Long> {
}

Мне нужно сделать запрос для поиска по schoolId и фильтрации всех полей по какой-либо строке.

Примерно так:

@Query("SELECT u FROM User u " +
        "WHERE u.schoolId = :schoolId AND (" +
        "u.id like %:searchVal% OR " +
        "u.name like %:searchVal% OR " +
        "u.isActive like %:searchVal%)")
Page<User> getUserBySchoolIdWithFilter(@Param("schoolId") Long schoolId,
                                       Pageable pageable,
                                       @Param("searchVal") String searchVal);

Но я получаю исключение, потому что я пытаюсь применить like к Long и Boolean.

Например, , если я пытаюсь фильтровать по «testSearchValue», я получаю следующее исключение:

java.lang.IllegalArgumentException: значение параметра [% testSearchValue%] не соответствует ожидаемому типу [java.lang.Long (n / a)

К сожалению, CAST и CONVERT у меня не сработали.

Так есть ли обходной путь?

НЕКОТОРЫЕ ДЕТАЛИ

Я отправляю GET запрос к этому API:

@RequestMapping(path = "users/{schoolId}/search", method = GET)
public ResponseEntity<Page<User>> searchUserBySchoolWithFilter(
                    @PathVariable(value = "schoolId") Long schoolId, Pageable pageable,
                    @RequestParam(value = "searchVal", required = false) String searchVal) {
    return new ResponseEntity<>(userService
                .getUserBySchoolIdWithFilter(schoolId, pageable, searchVal), HttpStatus.OK);
    }

Затем в UserService:

public Page<User> getUserBySchoolIdWithFilter(Long schoolId, Pageable pageable, String searchVal) {
    return userRepositoryPageable.getUserBySchoolIdWithFilter(schoolId, pageable, searchVal);
}

Итак:

Насколько я понимаю, основной вопрос заключается в том, чтобы представлять Long и Boolean как String.
Может лучше использовать nativeQuery? Если да, то не могли бы вы дать мне подсказку о том, как использовать CAST() или CONVERT() с предложением LIKE?

1 Ответ

0 голосов
/ 30 июня 2018

Рассматривали ли вы использование Технические характеристики ?

Используя спецификации, вы можете динамически генерировать часть WHERE запроса данных пружины. Чтобы использовать спецификации с вашими запросами JPA на данные пружины, вам нужно будет расширить интерфейс org.springframework.data.jpa.repository.JpaSpecificationExecutor. Таким образом, ваш пользовательский репозиторий может выглядеть так:

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}

Ваш метод поиска может выглядеть следующим образом

public List<User> getAllFilterByString(String text) {

    if(StringUtils.isEmpty(text))
        return userRepository.findAll();

    Specification<User> specification =
            (root, query, cb) -> {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(cb.like(cb.lower(root.get("name")), "%"+text.toLowerCase()+"%"));

                //check if the text value can be casted to long.
                //if it is possible, then add the check to the query
                try {
                    long longValue = Long.valueOf(text);
                    predicates.add(cb.equal(root.get("id"), longValue));
                }
                catch (NumberFormatException e) {
                    //do nothing, the text is not long
                }

                //check if the text can be casted to boolean
                //if it is possible, then add the check to the query

                Boolean value = "true".equalsIgnoreCase(text) ? Boolean.TRUE :
                        "false".equalsIgnoreCase(text) ? Boolean.FALSE : null;

                if(value != null) {
                    predicates.add(cb.equal(root.get("isActive"), value));
                }

                return cb.or(predicates.toArray(new Predicate[] {}));
            };

    return userRepository.findAll(specification);

}

Сначала мы начнем с добавления name LIKE %text% части выражения where.

Далее мы проверяем, можно ли привести значение переменной text к long. Если это возможно, то мы извлекаем длинное значение из строки и добавляем его в запрос where.

Последнее, что мы проверяем, может ли переменная text быть приведена к логическому значению. Если это возможно, то мы добавляем эту проверку и к запросу.

Например, если значение переменной text равно test1 , то часть где будет

WHERE name LIKE '%test1%;

Если значение переменной text равно true , то часть where будет

WHERE name LIKE '%true%' OR is_active = true;

Наконец, если значение переменной text равно 12 , то часть where будет

WHERE name LIKE '%12%' OR id = 12;

Примечание: Я добавил cb.lower(root.get("name")) и text.toLowerCase() к детали при поиске по имени, чтобы сделать поиск нечувствительным к регистру.

...