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

Spring Boot多对多关联实体如何通过原生查询填充Category列表

用原生SQL填充Product实体及关联的Categories列表

原生SQL查询默认不会自动填充@ManyToMany关联的集合属性,需要通过手动组装结果或者结合JPA结果集映射来实现,以下是具体方案:

一、基础关联SQL语句

首先需要关联product、product_category(中间表)、category三张表,查询所有产品及其关联分类:

SELECT 
    p.pid, p.name, 
    c.cid, c.catname, c.desc
FROM product p
LEFT JOIN product_category pc ON p.pid = pc.pro_id
LEFT JOIN category c ON pc.cat_id = c.cid

注意:检查你的中间表名是否为product_category(你的实体代码中写的是product_category ,末尾有空格,需和数据库实际表名一致,否则会报错)


二、方案一:手动组装结果(简单直接)

1. 定义Repository查询方法

返回查询结果的原始数组,包含产品和分类的所有字段:

@Query(value = "SELECT p.pid, p.name, c.cid, c.catname, c.desc FROM product p LEFT JOIN product_category pc ON p.pid = pc.pro_id LEFT JOIN category c ON pc.cat_id = c.cid", nativeQuery = true)
List<Object[]> findAllProductsWithCategories();

2. 在Service层组装实体

遍历查询结果,通过Map去重产品,将分类添加到对应产品的Categories列表中:

public List<Product> getProductList() {
    List<Object[]> rawResults = productRepository.findAllProductsWithCategories();
    Map<Integer, Product> productMap = new HashMap<>();

    for (Object[] row : rawResults) {
        // 提取产品字段
        Integer pid = (Integer) row[0];
        String productName = (String) row[1];
        // 提取分类字段(可能为null,因为用了LEFT JOIN)
        Long cid = row[2] != null ? (Long) row[2] : null;
        String catName = row[3] != null ? (String) row[3] : null;
        String catDesc = row[4] != null ? (String) row[4] : null;

        // 从Map中获取或创建Product实例
        Product product = productMap.get(pid);
        if (product == null) {
            product = new Product();
            product.setPid(pid);
            product.setName(productName);
            product.setCategories(new ArrayList<>());
            productMap.put(pid, product);
        }

        // 如果分类存在,添加到产品的分类列表
        if (cid != null) {
            Category category = new Category();
            category.setCid(cid);
            category.setCatname(catName);
            category.setDesc(catDesc);
            product.getCategories().add(category);
        }
    }

    return new ArrayList<>(productMap.values());
}

三、方案二:结合JPA结果集映射

通过@SqlResultSetMapping定义实体与查询结果的映射关系,再手动组装集合:

1. 定义结果集映射

在Product实体类上添加@SqlResultSetMapping注解:

@Entity
@SqlResultSetMapping(
    name = "ProductWithCategoriesMapping",
    entities = {
        @EntityResult(
            entityClass = Product.class,
            fields = {
                @FieldResult(name = "pid", column = "pid"),
                @FieldResult(name = "name", column = "name")
            }
        ),
        @EntityResult(
            entityClass = Category.class,
            fields = {
                @FieldResult(name = "cid", column = "cid"),
                @FieldResult(name = "catname", column = "catname"),
                @FieldResult(name = "desc", column = "desc")
            }
        )
    }
)
public class Product {
    // 原有代码不变
}

2. 定义Repository查询方法

引用上述结果集映射,返回包含Product和Category实例的数组:

@Query(value = "SELECT p.pid, p.name, c.cid, c.catname, c.desc FROM product p LEFT JOIN product_category pc ON p.pid = pc.pro_id LEFT JOIN category c ON pc.cat_id = c.cid", nativeQuery = true)
@SqlResultSetMapping(name = "ProductWithCategoriesMapping")
List<Object[]> findAllProductsWithCategories();

3. 在Service层组装实体

遍历结果数组,去重产品并关联分类:

public List<Product> getProductList() {
    List<Object[]> rawResults = productRepository.findAllProductsWithCategories();
    Map<Integer, Product> productMap = new HashMap<>();

    for (Object[] row : rawResults) {
        Product product = (Product) row[0];
        Category category = (Category) row[1];

        // 去重产品
        Product existingProduct = productMap.get(product.getPid());
        if (existingProduct == null) {
            product.setCategories(new ArrayList<>());
            productMap.put(product.getPid(), product);
            existingProduct = product;
        }

        // 添加分类(注意过滤null,避免空指针)
        if (category != null && category.getCid() != null) {
            existingProduct.getCategories().add(category);
        }
    }

    return new ArrayList<>(productMap.values());
}

内容的提问来源于stack exchange,提问作者Gökhan Şahiner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:15:39