Spring JPA @Query结合Specification与参数时抛可选参数异常
JPA联合分页、Specification与自定义参数查询报错解决
问题场景
编写JPA复杂查询时,需要同时实现分页、Specification过滤和额外自定义参数的协同工作,定义了如下Repository方法:
@Query(value = QRY_DATA, countQuery = QRY_DATA_COUNT) Page<NotificationUserSettingsPageResponse> findAllFrontend(@Nullable Specification<NotificationUserSettings> spec, Pageable pageable, @Param("user_UUID") String userUUID);
执行该方法时触发报错:
but parameter 'Optional[spec]' not found in annotated query
移除最后一个userUUID参数后方法可正常运行,但添加该参数后,JPA会错误地将Specification当作查询参数去匹配注解SQL中的占位符。需要说明的是,user_UUID参数用于关联查询的ON子句中,无法移入Specification内处理,具体查询语句如下:
SELECT new pl.notification.dto.response.NotificationUserSettingsPageResponse(s.id, s.userUUID, n.id, n.system, n.name, n.category, b.id, b.businessRule, CASE WHEN s.id > 0 THEN s.isEmail ELSE 'T' END AS is_email, CASE WHEN s.id > 0 THEN s.isSMS ELSE 'T' END AS is_sms, CASE WHEN s.id > 0 THEN s.isPortal ELSE 'T' END AS is_portal) FROM BusinessRuleConfig b RIGHT JOIN NotificationConfig n on n.id = b.notificationConfig.id LEFT JOIN NotificationUserSettings s on s.id = n.id AND s.id = b.id AND s.userUUID =:user_UUID
解决方案
问题核心是Spring Data JPA对混合使用@Query注解和Specification的参数顺序有严格要求:当同时使用Specification和自定义@Param参数时,必须把Specification放在所有自定义参数的后面,否则JPA会错误解析参数类型。
修改后的Repository方法如下:
@Query(value = QRY_DATA, countQuery = QRY_DATA_COUNT) Page<NotificationUserSettingsPageResponse> findAllFrontend(Pageable pageable, @Param("user_UUID") String userUUID, @Nullable Specification<NotificationUserSettings> spec);
补充说明
- 同步修改分页总数查询语句(
QRY_DATA_COUNT),确保里面也包含:user_UUID占位符,否则分页总数计算会报错。示例count查询:
SELECT COUNT(DISTINCT n.id) FROM BusinessRuleConfig b RIGHT JOIN NotificationConfig n on n.id = b.notificationConfig.id LEFT JOIN NotificationUserSettings s on s.id = n.id AND s.id = b.id AND s.userUUID =:user_UUID
Specification作为动态查询条件的载体,必须处于参数列表末尾,这样JPA才能正确识别它是用于拼接动态查询的特殊参数,而非普通SQL占位符参数。
内容的提问来源于stack exchange,提问作者Piotr Lepa
相关产品推荐
相关产品推荐

