Dapper怎么处理多对多关系 Dapper many-to-many查询映射

1次阅读

Dapper通过手动JOIN中间表+MultiMapping+字典缓存实现多对多映射,核心是sql扁平查询、splitOn分割字段、内存重组对象树;需注意LEFT JOIN处理空关联、字段别名防冲突、集合初始化及大数据性能优化

Dapper怎么处理多对多关系 Dapper many-to-many查询映射

Dapper 本身不自动处理多对多关系,但通过手动编写连接查询 + MultiMapping 配合字典缓存,就能干净地映射出带集合的嵌套对象,比如“商品拥有多个分类”或“文章属于多个标签”。

核心思路:用中间表 JOIN + splitOn 分割 + 字典去重组装

多对多在数据库中一定有中间表(如 ProductCategory、PostTag)。Dapper 要做的不是“自动识别关系”,而是把 JOIN 后的扁平结果,按逻辑重新组织成对象树。

  • SQL 必须 select 主表字段 + 中间表字段 + 关联表字段(注意别名防冲突)
  • Query<t1 t2 tresult></t1> 多参数泛型方法,指定主实体、关联实体和返回类型
  • splitOn 值必须设为关联表的第一个字段名(如 CategoryId),告诉 Dapper 从哪一列开始映射第二个类
  • Dictionary<int t></int> 缓存已创建的主对象,避免同一主记录因多条关联行被重复实例化

典型代码示例:Product ←→ Category

假设三张表:Products(Id, Name)Categories(Id, Name)ProductCategories(ProductId, CategoryId)

Dapper怎么处理多对多关系 Dapper many-to-many查询映射

Text-To-Pokemon口袋妖怪

输入文本生成自己的Pokemon,还有各种选项来定制自己的口袋妖怪

Dapper怎么处理多对多关系 Dapper many-to-many查询映射 1487

查看详情 Dapper怎么处理多对多关系 Dapper many-to-many查询映射

var sql = @"   SELECT p.Id, p.Name,          c.Id AS CategoryId, c.Name AS CategoryName   FROM Products p   INNER JOIN ProductCategories pc ON p.Id = pc.ProductId   INNER JOIN Categories c ON pc.CategoryId = c.Id";  var products = new Dictionary<int, Product>(); connection.Query<Product, Category, Product>(sql,   (product, category) =>   {     if (!products.TryGetValue(product.Id, out var p))     {       p = product;       p.Categories = new List<Category>(); // 初始化集合       products.Add(p.Id, p);     }     p.Categories.Add(category);     return p;   },   splitOn: "CategoryId" );  return products.Values.ToList();

注意:这里 splitOn: "CategoryId" 是关键——因为 SQL 中 c.Id AS CategoryId 是关联表字段的起始列,Dapper 才知道前面是 Product,后面是 Category。

注意事项和避坑点

  • 如果某商品没有分类,INNER JOIN 会丢掉该商品;改用 LEFT JOIN 可保留,但需判断 category.Id == NULL 再决定是否添加
  • 字段名冲突必须用 AS 别名(如 p.Id AS ProductId, c.Id AS CategoryId),否则 splitOn 无法准确定位
  • 主实体的集合属性(如 Categories)必须在首次创建时初始化,否则 Add() 会报空引用
  • 不推荐一次性查超大结果集(比如 1000 个商品 × 平均 5 个分类 = 5000 行),性能瓶颈在内存组装;数据量大时考虑分页或两次查询(先查主表,再用 IN 查关联)

基本上就这些。多对多没那么神秘,本质还是“一次查平、内存聚拢”。只要 SQL 写对、splitOn 指对、字典用对,结构就稳了。

text=ZqhQzanResources