链式调用JPA Specification时,排序Specification的toPredicate返回值问题
问题:Specification排序方法的toPredicate应该返回什么?
我需要实现一个基于Spring Data JPA Specification的分页查询,替代原有原生SQL查询,要求固定按created_on列降序排序,不需要判断排序参数是否存在。
我写了一个用于排序的Specification,打算在链式调用其他查询条件Specification之后最后调用,代码如下:
匿名内部类写法
public static Specification<Event> orderByCreationDate() { return new Specification<Event>() { @Override public Predicate toPredicate(Root<Event> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { query.orderBy(criteriaBuilder.desc(root.get("created_on"))); return null; } }; }
Lambda简化写法
public static Specification<Event> orderByCreationDate() { return (root, query, criteriaBuilder) -> { query.orderBy(criteriaBuilder.desc(root.get("created_on"))); return null; }; }
完整链式调用代码
Page<Event> eventsPage = historyLogRepository.findAllPaginated( allEventsWithEventTypesByVaultId(vaultId) .and(hasNoEventTypeVisibility()).or(hasEventTypeVisibility(visibilities)) .and(hasNoEventTypes()).or(hasEventTypes(types)) .and(creationDateBefore(before)) .and(creationDateAfter(after)) .and(hasNoDocumentId()).or(hasDocumentId(documentId)) .and(orderByCreationDate()), pageable);
原有原生SQL查询(参考)
@Query(value = "SELECT * FROM event e " + "INNER JOIN event_type et ON et.id = e.event_type_id " + "WHERE e.vault_id = :vaultId AND " + "(COALESCE(:visibilities) IS NULL OR et.visibility IN (:visibilities)) AND " + "(COALESCE(:types) IS NULL OR et.name in (:types)) AND " + "(:before IS NULL OR e.created_on < :before) AND " + "(:after IS NULL OR e.created_on > :after) AND " + "(:documentId IS NULL OR e.document_id = :documentId) " + "ORDER BY e.created_on DESC LIMIT :limit", nativeQuery = true) List<Event> findAll(@Param("vaultId") String vaultId, @Param("before") LocalDateTime before, @Param("after") LocalDateTime after, @Param("limit") Integer maxNumberOfResults, @Param("types") List<String> types, @Param("visibilities") List<String> visibilities, @Param("documentId") String documented);
新Repository方法定义
Page<Event> findAllPaginated(Specification<Event> specification, Pageable pageable);
请问此时该排序Specification的toPredicate方法应该返回什么?
答案
直接返回null是完全可行的,因为这个Specification的作用仅在于添加排序规则,不需要贡献任何查询条件(Predicate)。
同时需要注意几个细节:
- 确保这个排序Specification是最后一个被链式调用的,避免后续的Specification修改
query.orderBy覆盖掉你的排序规则。 - 如果你传入的
Pageable参数中已经包含了排序配置,它会覆盖你在Specification中设置的排序。如果要强制使用created_on降序,要么确保传入的Pageable无排序规则,要么在Specification中先清空已有排序再添加:query.getOrderList().clear(); query.orderBy(criteriaBuilder.desc(root.get("created_on"))); - 建议使用实体类的属性名而非数据库列名,比如如果
Event实体中对应的属性是createdOn(驼峰命名),应该用root.get("createdOn")替代"created_on",更符合JPA规范,也能避免列名变更带来的问题。
内容的提问来源于stack exchange,提问作者belgoros
相关产品推荐
相关产品推荐

