Dapper 多表 Object-Relation Mapping

上个博客讲解了SQL参数映射和单表结果的映射, 这篇博客聚焦于多表查询结果的映射.

=====================================

一对一映射

=====================================

以订单和客户为例, 业务对象和后台表正好是对齐的, 两个实体对象分别对应这两个后台表, 而且订单表的客户和客户表是1:1对应关系.

对象模型类:

public class Customer
{
    public string CustomerId { get; set; } = "";
    public string customerName { get; set; } = "";
    public int? Age { get; set; }
}

public  class Order
{
    public string OrderId { get; set; } = "";
    public string OrderDate { get; set; } = "";
    public string Customerid { get; set; } = "";
    public Customer Customer { get; set; } = new Customer();  //关联 Customer 对象
}

后台数据表:

-- 订单表
select 1 OrderId, 'c1' CustomerId, '2021-11-13' OrderDate 
union all 
select 2 OrderId, 'c2' CustomerId, '2021-11-13' OrderDate  
union all
select 3 OrderId, 'c1' CustomerId, '2021-12-13' OrderDate  
union all 
select 4 OrderId, 'c2' CustomerId, '2021-12-13' OrderDate 
;

-- 客户表
select 'c1' CustomerId, 'c1name' customerName,  10 Age 
union all 
select 'c2' CustomerId, 'c2name' customerName,  20 Age 
union all 
select 'c3' CustomerId, 'c3name' customerName,  30 Age 
;

需求: 我们需要通过一次查询DB获取全部的订单对象, 注意每个订单对象中包含了一个Customer对象.

一对一关联查询语句为:

select o.OrderId, o.CustomerId, o.OrderDate,c.CustomerId, c.customerName, c.age from 
(
select 1 OrderId, 'c1' CustomerId, '2021-11-13' OrderDate 
union all 
select 2 OrderId, 'c2' CustomerId, '2021-11-13' OrderDate  
union all
select 3 OrderId, 'c1' CustomerId, '2021-12-13' OrderDate  
union all 
select 4 OrderId, 'c2' CustomerId, '2021-12-13' OrderDate  
) o 
join  
(
select 'c1' CustomerId, 'c1name' customerName,  10 Age 
union all 
select 'c2' CustomerId, 'c2name' customerName,  20 Age 
union all 
select 'c3' CustomerId, 'c3name' customerName,  30 Age 
) c on o.customerId=c.CustomerId 

Dapper Query() 支持从大宽查询结果中一次性地填充多个对象,我们对重载形式做一些解读:

 IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param = null ) 

  第一个参数是SQL, 第二个参数是对象之间的map匿名函数, 共4个对象, 前三个对象Dapper query()函数能能自动填充, 第四个对象用于告知Dapper返回对象类型是什么.

 这里就出现了一个问题, Dapper是如何将一个宽的结果集分成三个部分,用于初始化前三个对象呢?

答案是, 通过 splitOn 参数来分割宽表结果集,splitOn 参数是要给逗号分隔的字符串, 用于设定分割字段, 比如取值为"SplitOn1,SplitOn2",

Dapper 会从右到左扫描各个列,最右的分割字段SplitOn2以及右边的所有将用于填充最右边的对象, 然后需要继续向左扫描,碰到前一个splitOn1字段,中间这几个字段将用于第二个对象,  剩余前面字段用于填充第一个字段.

 在Order和 Customer 示例中,  是两个对象之间的关系, 而且是一对一关系,  直接将传入的 customerObj 赋值给 orderObj.Customer属性, 即完成1:1对象绑定

public string SelectTest6()
{ 
    using (IDbConnection conn = new SqlConnection(_connectionString))
    {
        string sql = @"select o.OrderId, o.CustomerId, o.OrderDate,c.CustomerId, c.customerName, c.Age from 
            (
            select 1 OrderId, 'c1' CustomerId, '2021-11-13' OrderDate 
            union all 
            select 2 OrderId, 'c2' CustomerId, '2021-11-13' OrderDate  
            union all
            select 3 OrderId, 'c1' CustomerId, '2021-12-13' OrderDate  
            union all 
            select 4 OrderId, 'c2' CustomerId, '2021-12-13' OrderDate  
            ) o 
            join  
            (
            select 'c1' CustomerId, 'c1name' customerName,  10 Age 
            union all 
            select 'c2' CustomerId, 'c2name' customerName,  20 Age 
            union all 
            select 'c3' CustomerId, 'c3name' customerName,  30 Age 
            ) c on o.customerId=c.CustomerId 
            ";
        var orderList = conn.Query<Order, Customer, Order>(sql, 
            (orderObj,customerObj)=> {
                orderObj.Customer = customerObj; //直接将传入的 customerObj 赋值给 orderObj.Customer属性, 即完成1:1对象绑定
                return orderObj;
            }, 
            splitOn: "CustomerId");
    }
    return "ok";        
}

检查一对一mapping结果如下:

=====================================

一对多映射

=====================================

订单主表 Order  和 订单明细表 orderLine 是一对多的关系.

对象模型代码:

public  class Order
{
    public string OrderId { get; set; } = "";
    public string OrderDate { get; set; } = "";
    public string Customerid { get; set; } = ""; 
    public List<OrderLine> OrderLines { get; set; } = new List<OrderLine>();
}

public class OrderLine
{
    public string OrderId { get; set; } = "";
    public string OrderLineId { get; set; } = "";
    public string productName { get; set; } = "";
    public int Qty { get; set; } = 0;
}

后台数据表:

--订单主表
select 1 OrderId, 'c1' CustomerId, '2021-11-13' OrderDate 
union all 
select 2 OrderId, 'c2' CustomerId, '2021-11-13' OrderDate  
union all
select 3 OrderId, 'c1' CustomerId, '2021-12-13' OrderDate  
union all 
select 4 OrderId, 'c2' CustomerId, '2021-12-13' OrderDate  
;

--订单明细表
select 1 OrderId, 'line1' OrderLineId, 'prod1' ProductName, 10 Qty
union all 
select 1 OrderId, 'line2' OrderLineId, 'prod2' ProductName, 10 Qty
union all 
select 2 OrderId, 'line3' OrderLineId, 'prod1' ProductName, 10 Qty
union all 
select 2 OrderId, 'line4' OrderLineId, 'prod1' ProductName, 10 Qty
union all 
select 3 OrderId, 'line5' OrderLineId, 'prod1' ProductName, 10 Qty
union all 
select 4 OrderId, 'line6' OrderLineId, 'prod1' ProductName, 10 Qty 
;

两表Join的结果如下:

因为是一对多的关系, 经过join后记录数多余订单主表的数量, 而我们的对象模型是以订单为主要对象,  所以O-R Mapping后要做一个去重处理, 即Order 对象整体还是要求只有4个, 对于orderId为1和2, 其OrderLine集合都有两条. 

https://riptutorial.com/dapper/example/1197/one-to-many-mapping

https://www.learndapper.com/relationships

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
博文地址: https://www.cnblogs.com/cl-blogs/p/10219126.html 简单栗子: [Test] public void 三表联表分页测试() { LockPers lpmodel = new LockPers() { Name = "%蛋蛋%", IsDel = false}; Users umodel = new Users() { UserName = "jiaojiao" }; SynNote snmodel = new SynNote() { Name = "%木头%" }; Expression<Func<LockPers, Users, SynNote, bool>> where = PredicateBuilder.WhereStart<LockPers, Users, SynNote>(); where = where.And((lpw, uw, sn) => lpw.Name.Contains(lpmodel.Name)); where = where.And((lpw, uw, sn) => lpw.IsDel == lpmodel.IsDel); where = where.And((lpw, uw, sn) => uw.UserName == umodel.UserName); where = where.And((lpw, uw, sn) => sn.Name.Contains(snmodel.Name)); DapperSqlMaker<LockPers, Users, SynNote> query = LockDapperUtilsqlite<LockPers, Users, SynNote> .Selec() .Column((lp, u, s) => // null) //查询所有字段 new { lp.Id, lp.InsertTime, lp.EditCount, lp.IsDel, u.UserName, s.Content, s.Name }) .FromJoin(JoinType.Left, (lpp, uu, snn) => uu.Id == lpp.UserId , JoinType.Inner, (lpp, uu, snn) => uu.Id == snn.UserId) .Where(where) .Order((lp, w, sn) => new { lp.EditCount, lp.Name, sn.Content }); var result = query.ExcuteSelect(); //1. 执行查询 WriteJson(result); // 打印查询结果 Tuple<StringBuilder, DynamicParameters> resultsqlparams = query.RawSqlParams(); WriteSqlParams(resultsqlparams); // 打印生成sql和参数 int page = 2, rows = 3, records; var result2 = query.LoadPagelt(page, rows, out records); //2. 分页查询 WriteJson(result2); // 查询结果 }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值