Spring Boot中JPA @Query语句报错,寻求合规改写方案
问题分析与解决方案
你的JPA查询报错的核心原因是JPQL(JPA查询语言)不支持在FROM子句中直接使用子查询(部分JPA实现如Hibernate 5.1+有限支持,但写法与原生SQL差异较大),同时语句还有两处细节错误:
- DTO构造缺少
new关键字,JPQL要求必须显式使用new来实例化自定义DTO GROUOP BY是拼写错误,应为GROUP BY
下面提供两种可行的改写方案:
方案一:使用原生SQL查询(最直接)
既然你的语句在PostgreSQL中能正常运行,直接将其改为JPA原生SQL查询即可,只需添加nativeQuery = true参数,同时修正DTO构造和分组字段的错误:
@Query(value = "SELECT books_query.name, count(travelA_query.customer_id) " + "FROM (SELECT DISTINCT customer_servant.employee_id, books.customer_id FROM customer_servant " + "INNER JOIN books ON customer_servant.employee_id = books.customer_servant_id) AS travelA_query " + "INNER JOIN " + "(SELECT travel_agency.id, travel_agency.name, employee.employee_id FROM travel_agency " + "INNER JOIN employee ON travel_agency.id = employee.travel_agency_id) AS books_query " + "ON travelA_query.employee_id = books_query.employee_id " + "GROUP BY books_query.name", nativeQuery = true) List<Object[]> getTravelAgencyCustomerCount();
若要直接返回DTO,需确保实体类或DTO有对应构造函数,或通过
@SqlResultSetMapping映射结果;也可先返回Object[]再手动转换为DTO。
方案二:改写为标准JPQL查询(推荐)
如果希望使用JPQL而非原生SQL,可利用实体间的关联关系重构查询,避免FROM子句的子查询。假设你的实体关联关系为:CustomerServant关联Books、Employee关联TravelAgency,改写后的语句如下:
@Query("SELECT new com.example.imse22.model.TrvlA_Cust_Dto(ta.name, COUNT(DISTINCT b.customerId)) " + "FROM CustomerServant cs " + "JOIN cs.books b " + "JOIN Employee e ON cs.employeeId = e.employeeId " + "JOIN e.travelAgency ta " + "GROUP BY ta.name") List<TrvlA_Cust_Dto> getTravelAgencyCustomerCount();
关键调整说明:
- 直接使用实体类和关联关系JOIN,替代原生SQL的子查询逻辑
- 显式添加
new关键字构造DTO,确保DTO有对应参数的构造函数 - 用
COUNT(DISTINCT b.customerId)替代原查询的去重子查询,实现相同业务逻辑 - 修正分组字段为
ta.name(原语句中travelA_query.name是错误关联,该子查询无name字段)
内容的提问来源于stack exchange,提问作者peebee
相关产品推荐
相关产品推荐

