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
相关产品推荐
相关产品推荐

