JPA搜索字符串,长整数和布尔值

时间:2018-06-30 09:14:08

标签: java mysql spring-boot jpql

我有一个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应用于LongBoolean

例如,如果我尝试通过“ testSearchValue”进行过滤,则会收到此异常:

  

java.lang.IllegalArgumentException:参数值[%testSearchValue%]与预期的类型[java.lang.Long(n / a)

”不匹配

很遗憾,CASTCONVERT并没有为我工作。

那么有什么解决方法吗?

一些细节

我向此API发送了一个GET请求:

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

所以:

据我所知,问题的基本要点是将LongBoolean表示为String
也许最好使用nativeQuery?如果是这样,那么您能给我一个关于如何在CAST()子句中使用CONVERT()LIKE的提示吗?

1 个答案:

答案 0 :(得分:2)

您是否考虑过使用Specifications

使用规范,您可以动态生成spring数据查询的WHERE部分。 为了在Spring数据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);

}

首先,我们从添加where表达式的name LIKE %text%部分开始。

接下来,我们检查text变量的值是否可以强制转换为long。如果可以,那么我们从字符串中获取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(),以使搜索大小写不敏感。