首页 > 解决方案 > JPA 搜索字符串、长整型和布尔型

问题描述

我有一个 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申请Longand Boolean

例如,如果我尝试按“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);
}

所以:

据我所知,问题的基本点是将Long和表示BooleanString
也许使用更好nativeQuery?如果是这样,那么你能给我一个关于如何使用CAST()CONVERT()withLIKE子句的提示吗?

标签: javamysqlspring-bootjpql

解决方案


您是否考虑过规范的使用?

使用规范,您可以动态生成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);

}

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

接下来,我们检查text变量的值是否可以强制转换为long. 如果可以,那么我们从字符串中获取长值并将其添加到 where 查询中。

最后我们检查text变量是否可以转换为布尔值。如果可以,那么我们也将该检查添加到查询中。

例如,如果text变量的值为test1,则 where 部分将是

WHERE name LIKE '%test1%;

如果text变量的值为,那么 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()部分,以使搜索不区分大小写。


推荐阅读