JPA search String, Long and Boolean

女生的网名这么多〃 提交于 2019-12-11 04:29:23

问题


I have a Spring-Boot app. There's an entity:

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

I have a repository:

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

I need to make a request to search by schoolId and filter all fields by some string.

Something like this:

@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);

But I receive an exception because I try to apply like to Long and Boolean.

For example, if I try to filter by "testSearchValue", I receive this exception:

java.lang.IllegalArgumentException: Parameter value [%testSearchValue%] did not match expected type [java.lang.Long (n/a)

Unfortunately, CAST and CONVERT haven't worked for me.

So is there any workaround?

SOME DETAILS

I send a GET request to this 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);
    }

Then in UserService:

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

So:

As far as I see it, the basic point of the question is to represent Long and Boolean as String.
Maybe it's better to use nativeQuery? If so, then could you give me a hint about how to use CAST() or CONVERT() with LIKE clause?


回答1:


Have you considered the usage of Specifications?

Using specifications, you can dynamically generate the WHERE part of a spring data query. In order to use specifications with your spring data JPA queries, you will have to extend the org.springframework.data.jpa.repository.JpaSpecificationExecutor interface. So your user repository could look like this:

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

Your search method could look like this

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);

}

First we start by adding the name LIKE %text% part of the where expression.

Next, we check if the value of the text variable can be cast to long. If it can, then we get the long value out of the string and add it to the where query.

Last we check if the text variable can be cast to boolean. If it can, then we add that check to the query as well.

For example, if the value of the text variable is test1 the where part will be

WHERE name LIKE '%test1%;

If the value of the text variable is true then the where part will be

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

Finally, if the value of the text variable is 12 then the where part will be

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

Note: I added cb.lower(root.get("name")) and text.toLowerCase() to the part when we search by name in order to make the search case insensitive.



来源:https://stackoverflow.com/questions/51113509/jpa-search-string-long-and-boolean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!