使用@Query搭配LocalDate参数查询抛出SQLGrammarException问题求助
问题原因分析
- 核心诱因1:
author字段的LIKE拼接写法错误,直接写%:#{#filter.author}%会将%识别为独立的查询片段,引发参数绑定错位,原本应该对应DATE类型的参数位置被其他类型参数占用,PostgreSQL无法匹配到预期的日期类型。 - 核心诱因2:PostgreSQL无法自动识别SpEL表达式返回的LocalDate参数的数据类型,在
is null判断分支中没有明确的类型上下文提示,进一步触发类型判定失败的错误。
可行解决方案
方案1:修正JPQL写法(成本最低,无需调整现有结构)
修正LIKE通配符拼接逻辑,同时显式指定日期参数类型,修改后的Repository查询代码如下:
@Query("SELECT r " + " FROM ResearchRequestEntity r " + " WHERE " + " (:#{#filter.content} is null OR r.content = :#{#filter.content}) AND " + " (:#{#filter.author} is null OR r.author LIKE CONCAT('%', :#{#filter.author}, '%')) AND " + " (:#{#filter.createdOn} is null OR r.createdOn <= CAST(:#{#filter.createdOn} AS java.time.LocalDate)) AND " + " (:#{#filter.status} is null OR r.status = :#{#filter.status})" ) Page<ResearchRequestEntity> findByFilter(FilterDto filter, Pageable pageable);
修改点说明:
- 用
CONCAT函数拼接模糊查询通配符,避免通配符和参数拆分导致的绑定错位 - 用
CAST显式将SpEL返回的日期参数转换为LocalDate类型,给PostgreSQL明确的类型提示
方案2:改用JPA Specification实现动态查询(可维护性更高)
如果后续筛选条件会频繁迭代,推荐用Specification实现动态查询,从根源上避免SpEL参数绑定的各类问题:
- 首先让Repository接口继承
JpaSpecificationExecutor<ResearchRequestEntity> - 编写筛选条件构造逻辑:
public static Specification<ResearchRequestEntity> buildFilterSpec(FilterDto filter) { return (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); if (filter.getContent() != null) { predicates.add(cb.equal(root.get("content"), filter.getContent())); } if (filter.getAuthor() != null) { predicates.add(cb.like(root.get("author"), "%" + filter.getAuthor() + "%")); } if (filter.getCreatedOn() != null) { predicates.add(cb.lessThanOrEqualTo(root.get("createdOn"), filter.getCreatedOn())); } if (filter.getStatus() != null) { predicates.add(cb.equal(root.get("status"), filter.getStatus())); } return cb.and(predicates.toArray(new Predicate[0])); }; }
- 调用时直接使用内置查询方法即可:
Page<ResearchRequestEntity> result = repository.findAll(buildFilterSpec(filter), pageable);
内容的提问来源于stack exchange,提问作者Newboz
相关产品推荐
相关产品推荐

