Spring Boot JPA原生查询映射非实体POJO报错求助
解决JPA原生查询映射到非实体POJO的问题
错误原因分析
你遇到的问题根源在于:
- 最初使用
@EntityResult时,该注解仅用于映射JPA实体类(需带@Entity注解且对应数据库表),但你的RevenueRank并非实体,因此抛出Unknown entity异常。 - 添加
@Entity注解后,Hibernate会认为该类对应数据库表,但实际不存在匹配的表,因此执行查询时触发GenericJDBCException。
正确解决方案
方案1:使用JPA标准的@SqlResultSetMapping + @ConstructorResult
这是JPA规范支持的方式,适用于非实体POJO的映射,无需将POJO标记为实体。
步骤1:修改RevenueRank类
使用@ConstructorResult替代@EntityResult,指定POJO的构造函数对应查询结果列:
@SqlResultSetMapping( name = "RevenueRankResult", classes = @ConstructorResult( targetClass = RevenueRank.class, columns = { @ColumnResult(name = "Id", type = Long.class), @ColumnResult(name = "Customer_Name", type = String.class), @ColumnResult(name = "Revenue", type = BigDecimal.class), @ColumnResult(name = "Client_Name", type = String.class), @ColumnResult(name = "CustomerRank", type = Integer.class) } ) ) @Data @AllArgsConstructor // 生成全参构造函数,需确保参数顺序与查询列一致 public class RevenueRank { private Long id; private String customerName; private BigDecimal revenue; private String clientName; private Integer customerRank; }
若未使用Lombok的
@AllArgsConstructor,需手动编写全参构造函数,参数顺序必须与@ColumnResult的顺序完全匹配。
步骤2:修改查询代码
调用createNativeQuery时,传入映射名称而非POJO类:
@Component public class AnalyticsPersistor { @PersistenceContext private EntityManager entityManager; public List<RevenueRank> fetchRevenuRanks(String clientName) { String revRankQuery = "SELECT Id, Higher_Level_Entity_Value as Customer_Name, Revenue, Client_Name," + "ROW_NUMBER() OVER(ORDER BY Revenue DESC) CustomerRank " + "FROM cooperai.analytics.tbl_master_analytics " + "where Client_Name LIKE CONCAT('%', :clientName,'%');"; Query revenueRankQuery = entityManager.createNativeQuery(revRankQuery, "RevenueRankResult"); revenueRankQuery.setParameter("clientName", clientName); return revenueRankQuery.getResultList(); } }
方案2:使用Spring Data JPA Projection(更简洁)
如果项目使用Spring Data JPA,可定义Projection接口实现自动映射,无需额外注解:
步骤1:定义Projection接口
接口方法名需与查询结果列的驼峰式命名对应(Spring会自动处理下划线转驼峰):
public interface RevenueRankProjection { Long getId(); String getCustomerName(); // 对应查询中的Customer_Name BigDecimal getRevenue(); String getClientName(); Integer getCustomerRank(); }
步骤2:通过Repository执行查询
创建Repository接口并编写原生查询:
@Repository public interface AnalyticsRepository extends JpaRepository<MasterAnalytics, Long> { @Query(value = "SELECT Id, Higher_Level_Entity_Value as Customer_Name, Revenue, Client_Name," + "ROW_NUMBER() OVER(ORDER BY Revenue DESC) CustomerRank " + "FROM cooperai.analytics.tbl_master_analytics " + "where Client_Name LIKE CONCAT('%', :clientName,'%')", nativeQuery = true) List<RevenueRankProjection> fetchRevenueRanks(@Param("clientName") String clientName); }
此处
MasterAnalytics是对应tbl_master_analytics表的实体类,需已存在。
方案3:使用Hibernate ResultTransformer(Hibernate特有)
若依赖Hibernate,可使用ResultTransformer直接映射到POJO,但该方式为Hibernate扩展,非JPA标准:
@Component public class AnalyticsPersistor { @PersistenceContext private EntityManager entityManager; public List<RevenueRank> fetchRevenuRanks(String clientName) { String revRankQuery = "SELECT Id, Higher_Level_Entity_Value as Customer_Name, Revenue, Client_Name," + "ROW_NUMBER() OVER(ORDER BY Revenue DESC) CustomerRank " + "FROM cooperai.analytics.tbl_master_analytics " + "where Client_Name LIKE CONCAT('%', :clientName,'%');"; Session session = entityManager.unwrap(Session.class); List<RevenueRank> result = session.createNativeQuery(revRankQuery) .setParameter("clientName", clientName) .setResultTransformer(Transformers.aliasToBean(RevenueRank.class)) .list(); return result; } }
注意:Hibernate 5.2+中
Transformers.aliasToBean已标记为过时,推荐优先使用方案1或方案2。
内容的提问来源于stack exchange,提问作者hotmeatballsoup
相关产品推荐
相关产品推荐

