Spring Boot中QuerydslPredicateExecutor按条件排序实现方案咨询
解决方案
报错根因
JpaSort.unsafe传入表达式的方式仅适配普通JPA Repository查询方法,当调用QuerydslPredicateExecutor的findAll(Predicate predicate, Pageable pageable)执行时,Spring Data Querydsl会强制将排序字段解析为实体属性,不会把传入的kpp=1识别为SQL表达式,因此抛出PropertyReferenceException异常。
两种适配多实体的实现方案
方案1:基于Querydsl构造通用排序逻辑(推荐)
你已经引入了Querydsl,可以直接构造OrderSpecifier实现自定义表达式排序,可抽为通用工具类适配所有50个实体的需求:
- 构造自定义排序规则示例:
// 以AttachmentPoint实体对应的Querydsl Q类为例 OrderSpecifier<?> customSort = Expressions .numberTemplate(Integer.class, "case when {0} = 1 then 1 else 0 end", QAttachmentPoint.attachmentPoint.kpp) .desc();
- 扩展通用Repository基类:
让所有你的Repository都继承自定义的基类接口,一次编写全量复用:
public interface BaseRepository<T, ID> extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T> { default Page<T> findAllWithCustomSort(Predicate predicate, Pageable pageable, OrderSpecifier<?>... customOrders) { // 构造Querydsl查询 JPQLQuery<T> query = new JPAQueryFactory(getEntityManager()) .selectFrom(QEntityPathResolver.INSTANCE.createPath(getDomainClass())); query.where(predicate); // 优先应用自定义排序规则,再应用Pageable自带的排序规则 if (customOrders != null && customOrders.length > 0) { query.orderBy(customOrders); } query.orderBy(QuerydslUtils.toOrderSpecifiers(pageable.getSort(), query.getMetadata().getEntityPath())); // 执行分页查询 long total = query.fetchCount(); List<T> content = total > pageable.getOffset() ? query.fetch() : Collections.emptyList(); return new PageImpl<>(content, pageable, total); } }
调用时直接传入构造好的自定义排序规则即可,原有Predicate和Pageable参数可以完全复用现有逻辑。
方案2:实体加虚拟映射字段(改动最小)
不需要动态调整排序规则的场景下,可以直接给实体加@Formula虚拟字段,不需要修改查询逻辑:
// 实体类增加字段 @Formula("kpp = 1") private Integer kppSort;
之后直接给Pageable添加普通排序规则即可正常调用原有findAll方法:
Sort.by(Sort.Direction.DESC, "kppSort");
该方案仅需要给每个实体加1行注解,适合批量处理固定排序规则的场景。
选型建议
- 排序规则需要动态传参的场景选方案1,灵活度更高,无实体侵入
- 排序规则固定的场景选方案2,代码改动量最小,原有调用逻辑完全不用调整
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

