Spring Data JPA多表关联查询指定列映射自定义对象方法咨询
Spring Data JPA 多表指定字段查询映射自定义DTO实现
你这个场景不需要查询全表字段,直接用JPA的投影映射就能实现,步骤如下:
第一步:调整自定义DTO类
Spring Data JPA做自定义结果映射,要求DTO有和查询字段匹配的构造方法,调整MessageData如下:
import java.util.Date; // 普通Java类即可,不需要加@Entity等JPA注解 @Getter @Setter @AllArgsConstructor // 用Lombok生成全参构造,不用Lombok就手写和字段顺序、类型完全匹配的构造方法 @NoArgsConstructor public class MessageData { private String status; private Double buyerRate; private String buyerName; private String buyerTel; private Long bidPrice; private Date sendTime; private String brand; private String model; }
第二步:在Repository接口中编写查询方法
两种常用实现方式,选一种即可。
方式一:原生SQL映射(最适配你已写好的SQL)
直接在AuctionBid对应的Repository接口(继承JpaRepository)中添加方法,设置nativeQuery=true执行原生SQL,注意给字段加正确的别名和表前缀:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.List; public interface AuctionBidRepository extends JpaRepository<AuctionBid, Long> { @Query(value = """ SELECT ab.status, ai.buyer_rate AS buyerRate, ga.buyer_name AS buyerName, ga.buyer_tel AS buyerTel, ab.bid_price AS bidPrice, ADDTIME(ga.complete_dt,"23:00:0.000000") AS sendTime, ai.brand, ai.model FROM auction_bid ab INNER JOIN goods_auction ga ON ab.goods_auction_idx=ga.idx INNER JOIN auction_info ai ON ga.auction_info_idx=ai.idx WHERE ab.is_success=1 and ab.status='008' """, nativeQuery = true) List<MessageData> getMessageDataList(); }
注意点:
- 原SQL没有给跨表同名字段加表前缀,容易报字段歧义错误,上面已经补全了字段所属表的前缀:buyer_rate属于auction_info表,buyer_name、buyer_tel、complete_dt属于goods_auction表,is_success属于auction_bid表。
- 查询字段的别名必须和
MessageData中的属性名完全一致(驼峰命名),否则会映射失败。
方式二:JPQL构造查询(兼容性更好)
如果不想依赖数据库特定语法,可以写JPQL,利用实体类已经配置好的关联关系直接连表,不需要手写join的on条件,JPA会自动根据外键映射关联:
@Query(value = """ SELECT new com.你的项目包路径.MessageData( ab.status, ab.goodsAuction.auctionInfo.buyerRate, ab.goodsAuction.buyerName, ab.goodsAuction.buyerTel, ab.bidPrice, function('ADDTIME', ab.goodsAuction.completeDt, '23:00:0.000000'), ab.goodsAuction.auctionInfo.brand, ab.goodsAuction.auctionInfo.model ) FROM AuctionBid ab WHERE ab.isSuccess = 1 AND ab.status = '008' """) List<MessageData> getMessageDataListByJpql();
注意点:
new后面要写MessageData的全限定类名(包名+类名),构造方法的参数顺序必须和MessageData类中属性从上到下的顺序完全一致,否则会报找不到构造方法的错误。function()是JPA提供的原生函数调用语法,可以直接调用MariaDB的ADDTIME函数。
常见踩坑
- 如果不用Lombok生成全参构造,手写构造方法的时候,参数类型、顺序必须和查询返回的字段一一对应。
- 这种连表查指定字段的写法不会触发懒加载的N+1问题,不需要把关联关系的fetch改成EAGER。
- 不要给
MessageData加@Entity注解,它不是数据库映射的实体类,只是普通的结果传输对象。
内容的提问来源于stack exchange,提问作者Adam Lee
相关产品推荐
相关产品推荐

