多级查询

导航查询特点

1、无配置开箱就用

对于其它ORM导航查询来说一般都需要实体配置实体的关联关系,而SqlSugar则开箱就用,除了给非数据库字段加上Ignore外没有任何配置

2、高性能

自动映射模式不会产生循环Sql读取的情况,比如一对多查询 查询1条记录 那么生成2条SQL,那么查询200条记录还是生成2条SQL,

有人说为什么是2条而不是1条呢,1条复杂的sql性能未必好过2条简单无聚合分组的sql,可以通在sqlserver界面把3条sql扔进去然后

看执行计划的开销比例,如果说1条Sql大于等于50%那么他的性能就低于2条SQL性能


1、一对一查询

使用Mapper一对一模式需要设置2-3个参数, Mapper( 1需要填充的子对象 ,2主表关联字段,3从表关联字段(默认为从表主键))

第一个参数:it.Order是填充的子对象 

第二个参数  it.OrderId是主表中关联字段

第三个参数  不填等于从表主键,也可以指定从表某个字段

其实就是 主表中的 it.OrderId 和从表中的主键进行关联 ,就能自动填充到 OrderItem.Order里面

//主表(OrderItem )中OrderId与从表(Order)中的主键关联     
var list= db.Queryable<OrderItem>().Mapper(it => it.Order, it => it.OrderId).ToList(); 
foreach(var item in list)
{
   Console.WriteLine(item.Order.Name);//输出子对象中的值
}

 public class OrderItem {
        [SugarColumn(IsPrimaryKey =true ,IsIdentity =true)]
        public int ItemId { get; set; }
        public string ItemCode { get; set; }
        public decimal Pirce { get; set; }
        public int OrderId { get; set; }
        [SugarColumn(IsIgnore =true)]
        public Order Order{ get; set; }
 }
 public class Order {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        public string Name { get; set; }
        [SugarColumn(IsIgnore = true)]
        public List<OrderItem> Items { get; set; }
}

下面语句等于同上面语句,当没有主键的时候可以手动指定从表字段

var list= db.Queryable<OrderItem>().Mapper(it => it.Order, it => it.OrderId , it.Order.Id ).ToList();

新功能:1对1模式中支持了条件过滤

var list= db.Queryable<OrderItem>()
                   .Mapper(it => it.Order, it => it.OrderId)
                   .Where(it=>it.Order.Name=="哈哈").ToList(); //我们可以使用2级对象属性进行筛选


2、一对多查询

根据子对象items中的OrderId与主表的主键进行关联

public class Order
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        public string Name { get; set; }
        [SugarColumn(IsIgnore = true)]
        public List<OrderItem> Items { get; set; }
    }
    public class OrderItem {
        [SugarColumn(IsPrimaryKey =true ,IsIdentity =true)]
        public int ItemId { get; set; }
        public string ItemCode { get; set; }
        public decimal Pirce { get; set; }
        public int OrderId { get; set; }
        [SugarColumn(IsIgnore =true)]
        public Order Order{ get; set; }
    }
  var list= db.Queryable<Order>().Mapper(it => it.Items, it => it.Items.First().OrderId).ToList();
  
  //最新版本支持筛选
    var list= db.Queryable<Order>()
              .Mapper(it => it.Items, it => it.Items.First().OrderId)
              .Where(it=>it.Items.Count()>0)//或者it.Items.Any()
              .ToList();


3、 多对多查询

 public class ABMapping
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int AId { get; set; }
        public int BId { get; set; }
        [SugarColumn(IsIgnore = true)]
        public A A { get; set; }
        [SugarColumn(IsIgnore = true)]
        public B B { get; set; }
    }
    public class A {
        [SugarColumn(IsPrimaryKey =true ,IsIdentity =true)]
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class B
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        public string Name { get; set; }
    }
  var list= db.Queryable<ABMapping>()
                .Mapper(it => it.A,it=>it.AId)
                .Mapper(it => it.B, it => it.BId).ToList();


4、 相同字段名映射

子表对象=子表对象.where(it=>it.OrgId==主表对象中的.OrgId)

    public class A {
        [SugarColumn(IsPrimaryKey =true ,IsIdentity =true)]
        public int Id { get; set; }
        public string Name { get; set; }
        public string OrgId { get; set; }
        [SugarColumn(IsIgnore =true)]
        public B B { get; set; }
    }
    public class B
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        public string Name { get; set; }
        public string OrgId { get; set; }
    }
   var list= db.Queryable<A>().Mapper(it => it.B,it=>it.OrgId).ToList();


5、无规律映射

1对1和1对多都是通过一个字段和主键进行的映射,如果没有主键呢,这个时候就需要指定2个字段进行映射


public class Tree
{
        [SqlSugar.SugarColumn(IsPrimaryKey =true)]
        public int Id { get; set; }
        public string Name { get; set; }
        public int ParentId { get; set; }
        [SqlSugar.SugarColumn(IsIgnore = true)]
        public Tree Parent { get; set; }
        [SqlSugar.SugarColumn(IsIgnore = true)]
        public List<Tree> Child { get; set; }
}
var list=db.Queryable<Tree>()
                   //parent=(select * from parent where id=it.parentid)
                   //     子表对象 =   指定主表映射字段     指定子表映射字段
                   .Mapper(it=>it.Parent,it=>it.ParentId, it=>it.Parent.Id)
                   //Child=(select * from parent where ParentId=it.id)
                    //     子表对象 =   指定主表映射字段     指定子表映射字段
                   .Mapper(it => it.Child, it => it.Id, it => it.Parent.ParentId)
                   .ToList();


6、自定义查询

当我们需要灵活进行多级查询时我们可以这么写

List<Order> list = db.Queryable<Order>().Mapper((order,cache)=> {

    orderItem.Items = db.Queryable<OrderItem>().Where(it => it.OrderId == order.Id).ToList();

}).ToList();//缺点性能差会引起循环


将上面的代码进行性能优化 ,功能一模一样 ,代码如下:

List<Order> list = db.Queryable<Order>().Mapper((order,cache)=> {
    //cache.get 内的方法永远只执行一次
    List<OrderItem> allOrderItems = cache.Get(ol => //ol的值等于db.queryable<order>().tolist()
    {
        //查询出所有的OrderId集合
        var allOrderIds = ol.Select(x => x.Id).ToList();
        //查询出N个OrderId所对应的OrderItem
        return db.Queryable<OrderItem>().In(it => it.OrderId, allOrderIds).ToList();
    });
    //allOrderItems已经查询出N个OrderId所需要的Iitem,我们在从allOrderItems取出我要的 
    orderItem.Items = allOrderItems.Where(it => it.OrderId == order.Id).ToList(); 
}).ToList();


实体

 public class Order
 {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }

        public string Name { get; set; }
        public decimal Price { get; set; }
        [SugarColumn(IsNullable = true)]
        public DateTime CreateTime { get; set; }
        [SugarColumn(IsNullable =true)]
        public int CustomId { get; set; }
        [SugarColumn(IsIgnore = true)]
        public List<OrderItem> Items { get; set; }
  }


7、N级查询,意思就是嵌套了N层一次性全部查询出来

 List<ZC_t_Lad> listLad = Context.Queryable<ZC_t_Lad>()
                     .Where(s => s.FBIZDATE == fBizDate && s.FSALERID == FsalerID)
                        //第二层 可以偷懒,用一对多 一对一 等方式 进行查询 
                        .Mapper(s => s.LadEntryList, s => s.FID)
                        //第三只能自定义查询 
                        .Mapper((s, cache) => {   
                                             
                         //可以断点调试 ,s.LadEntiryList 在第二层查询中已经赋过值了
                             foreach(var t in s.LadEntryList)
                             {
                              t.MATERIAL=Context.Queryable<T_BD_MATERIAL>()
                                 .Where(o => o.FMATERIALID == t.FMATERIALID)
                                 .First();//给第三层赋值
                               }
                               
                              });
                            })
                           //.Mapper((s,acche)) 可以实现第四层查询
                        .ToList();
                        
//上面的写法查第一层和第二层不管多少条记录只会产生2条Sql,但是查第三层的时候会产生多条查询
//了解Mapper原理之后,对性能要求高的页面,我们可以用 cache.get进行优化(示例6和示例8 )


8、多对多中间表查询运用自定义Mapper Cache实现

var list = db.Queryable<用户>()

          .Mapper((result, cache) =>
            {
                  var allMps = cache.Get<List<用户职位中间表>>(l =>
                  {
                      //查出N个用户所需要的中间表
                      var cres = db.Queryable<用户职位中间表>()
                        .Mapper(y => y.职位, y => y.职位id)
                        .In(it => it.用户id, l.Select(it => it.Id).ToArray())
                        .ToList();
                      return cres;
                  });
                  //获取当前用户所需要的中间表
                  result.职位 = allMps
                                  .Where(it => it.用户id == result.Id)
                                  .Select(it => it.职位)
                                  .ToList();

         }).ToList();
         
         
public class 用户
{
  [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }

   public string Name { get; set; }
 
   [SugarColumn(IsIgnore = true)]
   public List<职位> 职位 { get; set; }
}
 
public class 用户职位中间表
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }
   public int 用户id { get; set; }
   public int 职位id { get; set; }
   [SugarColumn(IsIgnore = true)]
    public 用户 用户 { get; set; }
   [SugarColumn(IsIgnore = true)]
   public 职位 职位 { get; set; }
}

public class 职位
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int ID { get; set; }
   public string ItemCode { get; set; }
   public decimal Pirce { get; set; }
}