You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Hibernate中如何将MySQL自定义查询结果映射到Java模型类

解决原生SQL多表查询结果映射到自定义DTO的问题

嘿,这个场景我太熟了!用原生SQL查多表数据后没法直接映射到自定义的FavoriteItem确实是个常见的小难题,给你三个实用的解决方案,你可以根据自己的需求选:

1. 用@SqlResultSetMapping + @ConstructorResult映射到DTO

这是最规范的原生SQL映射方式,适合需要完整FavoriteItem对象的场景:

首先,确保你的FavoriteItem是一个普通POJO(不需要加@Entity注解,因为它只是数据传输对象),并且有一个和查询字段顺序匹配的构造函数:

public class FavoriteItem {
    private Long itemId;
    private String itemName;
    private String sizeName;
    private BigDecimal prices;

    // 要和查询返回的字段顺序完全对应
    public FavoriteItem(Long itemId, String itemName, String sizeName, BigDecimal prices) {
        this.itemId = itemId;
        this.itemName = itemName;
        this.sizeName = sizeName;
        this.prices = prices;
    }

    // 别忘了加getter/setter
}

接下来,在任意一个你的实体类上(比如MtItem实体)定义结果集映射:

@Entity
@Table(name = "mt_item")
@SqlResultSetMapping(
    name = "FavoriteItemMapping", // 这个名字要和后面@Query里的对应
    classes = @ConstructorResult(
        targetClass = FavoriteItem.class,
        columns = {
            @ColumnResult(name = "item_id", type = Long.class),
            @ColumnResult(name = "item_name", type = String.class),
            @ColumnResult(name = "size_name", type = String.class),
            @ColumnResult(name = "Prices", type = BigDecimal.class)
        }
    )
)
public class MtItem {
    // 你的实体字段和注解
}

最后修改你的Repository方法,指定resultSetMapping:

@Query(value = "Select i.item_id,i.item_name,s.size_name,sp.Prices from mt_item i join mt_sizeprice sp on i.item_id= sp.item_id join mt_size s on sp.size_id=s.size_id where i.merchant_fk= ?1 and is_featured=1",
       nativeQuery = true,
       resultSetMapping = "FavoriteItemMapping")
List<FavoriteItem> get(long merchantId);

这样查询结果就会自动映射成List<FavoriteItem>啦!

2. 用投影接口(轻量方案)

如果不需要完整的FavoriteItem对象,只是要获取这些字段,投影接口是更简单的选择:

先定义一个投影接口,方法名要和查询字段的别名对应(注意驼峰命名):

public interface FavoriteItemProjection {
    Long getItemId(); // 对应查询里的item_id AS itemId
    String getItemName(); // 对应item_name AS itemName
    String getSizeName(); // 对应size_name AS sizeName
    BigDecimal getPrices(); // 对应Prices AS prices
}

然后修改你的查询语句,给每个字段加别名,同时返回类型改成List<FavoriteItemProjection>:

@Query(value = "Select i.item_id AS itemId, i.item_name AS itemName, s.size_name AS sizeName, sp.Prices AS prices from mt_item i join mt_sizeprice sp on i.item_id= sp.item_id join mt_size s on sp.size_id=s.size_id where i.merchant_fk= ?1 and is_featured=1",
       nativeQuery = true)
List<FavoriteItemProjection> get(long merchantId);

Spring会自动生成这个接口的代理实现类,你直接调用getter方法就能拿到数据,甚至可以把它转换成FavoriteItem对象:

List<FavoriteItemProjection> projections = yourRepository.get(merchantId);
List<FavoriteItem> favoriteItems = projections.stream()
    .map(p -> new FavoriteItem(p.getItemId(), p.getItemName(), p.getSizeName(), p.getPrices()))
    .collect(Collectors.toList());

3. 手动映射(应急方案)

如果只是临时解决,不想改太多代码,也可以手动把Object[]数组转换成FavoriteItem:

先把Repository方法的返回类型改成List<Object[]>:

@Query(value = "Select i.item_id,i.item_name,s.size_name,sp.Prices from mt_item i join mt_sizeprice sp on i.item_id= sp.item_id join mt_size s on sp.size_id=s.size_id where i.merchant_fk= ?1 and is_featured=1",nativeQuery = true)
List<Object[]> get(long merchantId);

然后在业务代码里手动遍历转换:

List<Object[]> rawResults = yourRepository.get(merchantId);
List<FavoriteItem> favoriteItems = new ArrayList<>();
for (Object[] row : rawResults) {
    FavoriteItem item = new FavoriteItem();
    item.setItemId((Long) row[0]);
    item.setItemName((String) row[1]);
    item.setSizeName((String) row[2]);
    item.setPrices((BigDecimal) row[3]);
    favoriteItems.add(item);
}

不过这种方法要注意字段顺序,如果SQL查询的字段顺序变了,代码就会出错,所以只适合临时用哦!


内容的提问来源于stack exchange,提问作者Avinaya Acharya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 08:12:34