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

Dapper一对多查询时Product的StoreProducts子集合未填充如何解决

Dapper一对多关联查询子集合未填充问题解决

问题原因

  • Dapper 原生的多映射Query重载仅支持一对一关系绑定,不会自动聚合父对象的子集合属性
  • 原有代码未手动给Product.StoreProducts属性赋值,且该属性未做默认初始化,默认值为null
  • 原有映射逻辑中StoreProduct.ProductId = Product.ProductId属于无效操作,关联查询返回的StoreProduct本身已携带正确的ProductId字段值,无需手动覆盖

解决方案

场景1:当前单条关联查询简化实现

你的查询条件已限定最多返回1条关联记录,直接在映射委托中初始化并填充子集合即可:

  1. (可选)先给Product的StoreProducts属性添加默认初始化,避免空引用:
public class Product
{
    public Guid ProductId { get; set; }
    public string Brand { get; set; }
    public string Model { get; set; }
    // 添加默认初始化
    public virtual List<StoreProduct> StoreProducts { get; set; } = new List<StoreProduct>();
}
  1. 修改查询映射逻辑:
string sql = "SELECT * FROM StoreProduct AS A INNER JOIN Product AS B ON A.ProductId = B.ProductId WHERE A.StoreProductId = @StoreProductId and A.StoreId = @StoreId";
var connection = AppDbContext.Database.GetDbConnection();
return connection.Query<StoreProduct, Product, Product>(
    sql, 
    (storeProduct, product) => 
    { 
        // 若未在实体中初始化,这里做兜底初始化
        product.StoreProducts ??= new List<StoreProduct>();
        // 将当前关联的StoreProduct添加到Product的子集合中
        product.StoreProducts.Add(storeProduct);
        // 可选:维护双向关联,给StoreProduct的Product属性赋值
        storeProduct.Product = product;
        return product; 
    }, 
    new { StoreProductId = storeProductId, StoreId = StoreID }, 
    splitOn: "ProductId")
.FirstOrDefault();

场景2:通用多结果一对多查询实现

如果查询会返回多个Product,每个Product对应多条StoreProduct,需要用字典做去重聚合,避免同一个Product被重复实例化:

string sql = "SELECT * FROM StoreProduct AS A INNER JOIN Product AS B ON A.ProductId = B.ProductId";
var connection = AppDbContext.Database.GetDbConnection();
var productDict = new Dictionary<Guid, Product>();

var productList = connection.Query<StoreProduct, Product, Product>(
    sql, 
    (storeProduct, product) => 
    {
        // 字典中不存在当前Product则存入
        if (!productDict.TryGetValue(product.ProductId, out var existingProduct))
        {
            existingProduct = product;
            existingProduct.StoreProducts = new List<StoreProduct>();
            productDict.Add(existingProduct.ProductId, existingProduct);
        }
        // 关联StoreProduct到当前Product
        existingProduct.StoreProducts.Add(storeProduct);
        storeProduct.Product = existingProduct;
        return existingProduct;
    }, 
    splitOn: "ProductId")
.Distinct() // 去重返回唯一的Product集合
.ToList();

注意事项

  • 泛型参数顺序需要和查询返回的列顺序完全匹配:你当前SQL先返回StoreProduct的所有列,再返回Product的所有列,所以泛型顺序<StoreProduct, Product, Product>是正确的
  • splitOn参数指定的是第二个映射对象的主键列名,你当前配置为ProductId符合要求

内容的提问来源于stack exchange,提问作者João Cardoso

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:24:05