【导航查询】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列

  1. 【开篇】.NET开源 ORM 框架 SqlSugar 系列
  2. 【入门必看】.NET开源 ORM 框架 SqlSugar 系列
  3. 【实体配置】.NET开源 ORM 框架 SqlSugar 系列
  4. 【Db First】.NET开源 ORM 框架 SqlSugar 系列
  5. 【Code First】.NET开源 ORM 框架 SqlSugar 系列
  6. 【数据事务】.NET开源 ORM 框架 SqlSugar 系列
  7. 【连接池】.NET开源 ORM 框架 SqlSugar 系列
  8. 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
  9. 【查询基础】.NET开源 ORM 框架 SqlSugar 系列
  10. 【排序用法】.NET开源 ORM 框架 SqlSugar 系列
  11. 【分组去重】.NET开源 ORM 框架 SqlSugar 系列
  12. 【联表查询】.NET开源 ORM 框架 SqlSugar 系列
  13. 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
  14. 【子查询】.NET开源 ORM 框架 SqlSugar 系列
  15. 【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列

💦万丈高楼平地起,做开发想要技术精进,必须要有扎实的基础功底。基础SQL查询语法一定要牢记于心,才能应对后面更为复杂的形势。

​​

1、导航查询特点

💥作用:主要处理主对象里面有子对象这种层级关系查询

1.1 无外键开箱就用

其它ORM导航查询 需要 各种配置或者外键,而 SqlSugar 则开箱就用,无外键,只需配置特性和主键就能使用

1.2 高性能优

查询 性能非常强悍 5.0.8.1+版本进行了性能优化

支持大数据分页导航查询

3.3 语法超级爽

cs 复制代码
 var list=db.Queryable<Test>()
           .Includes(t=> t.Provinces, pro=>pro.Citys ,cit=>cit.Street) //多层级
           .Includes(t=> t.ClassInfo)// 一个层级查询
           .ToList();              
                
 //具体用法看下面文档介绍
 //多层级可以看2.5

2、新导航查询

适合有主键的常规操作, 请升级到5.0.6.8

2.1.1 一对一 ( one to one )

cs 复制代码
//实体
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int StudentId { get; set; }
    public string Name { get; set; }
    public  string SexCode { get;set;}
    public int SchoolId { get; set; }
     
    //用例1:主键模式 StudentA(主表)表中的 SchoolId 和SchoolA(子表)中的主键关联 
    [Navigate(NavigateType.OneToOne, nameof(SchoolId))]//一对一 SchoolId是StudentA类里面的
    public SchoolA SchoolA { get; set; } //不能赋值只能是null
     
    //用例2:反向导航,2个字段匹配关系 
    [Navigate(NavigateType.OneToOne,nameof(SchoolId),nameof(SchoolA.Id))]//变量名不要等类名 
    public SchoolA SchoolItem { get; set; } //不能赋值只能是null
    //第一个主表字段,第二从表字段  顺序不要错了
     
    //用例3: 字典导航 多了个SQL条件参数  
    //[SqlSugar.Navigate(NavigateType.OneToOne,nameof(SexId),nameof(DataDictionary1.Code),"type='sex'")]
    //具体用法可以看配置查询 https://www.donet5.com/Home/Doc?typeId=2309
 
}
public class SchoolA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id{ get; set; }
    public string SchoolName { get; set; }
} 
 
//导航+主表过滤  导航属性过滤
var list = db.Queryable<StudentA>()
         .Includes(x => x.SchoolA) //填充子对象 (不填充可以不写)
         .Where(x =>x.SchoolA.SchoolName=="北大") 
         .ToList();
 
 
//导航+主表过滤  只查有导航数据 (新功能:5.1.2.8)
var list = db.Queryable<StudentA>()
         .Includes(x => x.SchoolA) //填充子对象 (不填充可以不写)
         .Where(x => SqlFunc.Exists(x.SchoolA.主键))
         .ToList();            
                          
          
//导航+子表过滤 5.0.9.4-preview06 请注意升级 
//创建一个扩展函数,默认是Class不支持Where
public static List<T> Where<T>(this T thisValue, Func<T,bool> whereExpression ) where T:class,new()
{
   return new List<T>() { thisValue };
} 
var list = db.Queryable<Student_003>()
          .Includes(x => x.school_001.Where(z=>z.Name=="a").ToList())//扩展的Where对子表进行过滤
          .ToList(); //5.0.9.4-preview06 才支持 请注意升级 请注意升级
 
//导航 指定字段 5.1.3.38
var list = db.Queryable<StudentA>()
         .Includes(x => x.SchoolA.ToList(it=>new SchoolA(){ Name =it.Name,id=it.Id})) 
         .ToList();                    
           
           
//只查一个字段写法1:   
var list = db.Queryable<StudentA>()
             .Where(x => x.id>1)  //Where和Select中别名要写一样
             .Select(x =>new { 
                x=x,
                SchoolName= x.SchoolA.SchoolName
             }).ToList();
              
//只查一个字段写法2:
[Navigate(NavigateType.OneToOne, nameof(SchoolId))] 
public SchoolA SchoolA { get; set; }   
[SugarColumn(IsIgnore=true)]//加IsIgnore
public string SchoolName{get=>this.SchoolA?.Name;}//?防止空引用

多字段1对1 看文档2.4

2.1.2 多对一 (many to oney)

多对一其实就是一对一,用法上差不多,只是多了一个参数

cs 复制代码
 //第一个参数:当前表字段 
 //第二个参数: 子表中字段
 [Navigate(NavigateType.OneToOne,nameof(WorkOrderId),nameof(Wo.Id))]
 public Wo Wo { get; set; }//不要给get set赋值
 
 //也可以这样
 [Navigate(NavigateType.ManyToOne,nameof(WorkOrderId),nameof(Wo.Id))]
 public Wo Wo { get; set; }//不要给get set赋值

用法:看一对一的教程就行了

2.2 一对多 ( one to many)

BookA(子表)中的 studenId 和 StudentA(主表)中的主键关联

cs 复制代码
//实体
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id{ get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
     
    //用例1:正常一对多
    [Navigate(NavigateType.OneToMany, nameof(BookA.studenId))]//BookA表中的studenId
    public List<BookA> Books { get; set; }//注意禁止给books手动赋值
     
    //用例2:反向导航支持:StudentA没有主键或者指定关系
    [Navigate(NavigateType.OneToMany, nameof(BookA.studenId),nameof(Id))] 
    public List<BookA> Books { get; set; }//注意禁止给books手动赋值
    //与一对一相反 第一个 从表字段,第二个主表字段
 
}
public class BookA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int BookId { get; set; }
    public string Name { get; set; }
    public int studenId { get; set; }
}
 
//例1:简单用法
var list = db.Queryable<StudentA>()
.Includes(x => x.Books)
.ToList();
 
//例2:支持Any和Count 对主表进行过滤 (子对象过滤看下面)
var list = db.Queryable<StudentA>()
.Includes(x => x.Books)
.Where(x => x.Books.Any())
//带条件的
//.Where(x => x.Books.Any(z=>z.Name=="jack")))
.ToList();
 
//例3: 没有Includes也可以使用过滤
var list2 = db.Queryable<StudentA>()
.Where(x => x.Books.Any())//Any中可以加条件 Any(z=>z.BookId==1)
.ToList();                         
 
 
//例4 Where子对象进行排序和过滤 (支持WhereIF)
var list = db.Queryable<StudentA>()
  .Includes(x => x.Books.Where(y => y.BookId > 0).OrderBy(y => y.BookId).ToList())
  .ToList();
   
//例5 主表+子表都过滤
var list = db.Queryable<StudentA>()
.Includes(x => x.Books.Where(it=>it.Name=="jack").ToList())//只过滤子表
.Where(x => x.Books.Any(z=>z.Name=="jack")))//通过子表过滤主表
.ToList();
   
//例6:Select指定字段
var list= db.Queryable<StudentA>()
           .Includes(x => x.Books.Select(z=>new BookA() { Names = z.Names }).ToList()) 
 
//例7:Select多层级  (结构:StudentAt->books->BookItems)      
var list= db.Queryable<StudentA>()
     .Includes(x => x.Books.Select(z=>new BookA(){Names=z.Name}.ToList(),it=>BookItems)) 
    .ToList();、//Includes中的Select只能是字段 ,不能导航对象           
            
            
//例8:OrderBy指定字段 (Skip Take可以分页)
var list= db.Queryable<StudentA>()
           .Includes(x => x.Books.OrderBy(z=>z.Id).ToList()) 
           .ToList();
            
//例9:Take取前几条
var list= db.Queryable<StudentA>()
           .Includes(x => x.Books.Take(10).ToList()) 
           .ToList();          
                       
            
//例10:DTO支持进行了强化   
看标题2.7        
            
            
//例11:一对多后还可用追加字段映射MappingField 如果以前是1个字关联,现在追加后就成了1+1       
db.Queryable<StudentA>().Includes(x => x.Books.MappingField(z=>z.字段,()=>x.字段).ToList() )
                .ToList();
//MappingField 和 Where区别
//MappingField MappingField用来指定2个对象的关系,Where只能当前表过滤不能和主表进行关联 
//MappingField 可以多个也可以和Where一起始用

非标准1对多 看文档2.4

2.3 多对多 ( many to many)

cs 复制代码
//实体
public class ABMapping1
{
    [SugarColumn(IsPrimaryKey = true)]//中间表可以不是主键
    public int AId { get; set; }
    [SugarColumn(IsPrimaryKey = true)]//中间表可以不是主键
    public int BId { get; set; }
}
public class A1
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; }
    [Navigate(typeof(ABMapping1), nameof(ABMapping1.AId), nameof(ABMapping1.BId))]//注意顺序
    public List<B1> BList { get; set; }//只能是null不能赋默认值
}
public class B1
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; }
    [Navigate(typeof(ABMapping1), nameof(ABMapping1.BId), nameof(ABMapping1.AId))]//注意顺序
    public List<A1> AList { get; set; }//只能是null不能赋默认值
}  
//例1:简单用法 直接填充B的集合,只要配置好特性非常简单
var list3= db.Queryable<A1>().Includes(x => x.BList).ToList(); 
 
 //例2:支持子对象排序和过滤 (支持WhereIF)
var list3= db.Queryable<A1>().Includes(x => x.BList.Where(z=>z.Id>0).ToList()).ToList(); 
 
 //例3:支持主表过滤  Any和Count
var list3= db.Queryable<A1>().Includes(x => x.BList)
                .Where(x=>x.BList.Any())//Any里面可以加条件 Any(z=>z.xxxx>0)
                .ToList();
 //例4主表+子表都过滤
var list = db.Queryable<StudentA>()
   .Includes(x => x.BList.Where(it=>it.Name=="jack").ToList())//只过滤子表
   .Where(x => x.BList.Any(z=>z.Name=="jack")))//通过子表过滤主表
   .ToList();               
                 
//不使用Includes一样可以过滤              
var list3= db.Queryable<A1>() 
                .Where(x=>x.BList.Any()) //可以加条件.Where(x=>x.BList.Any(z=>z.xxx==x.yyy))
                .ToList();                
                 
//A表和B表不是主键情况多了2个参数 
//升级到: SqlSugarCore 5.1.4.147-preview16+
[Navigate(typeof(OptRole), 
          nameof(OptRole.operId), //中间表 aid
           nameof(OptRole.roleId),//中间表 bid
            nameof(OperatorInfo.id),//a表 id
               nameof(Role.id2))] //b表id
  public List<Role> Roles { get; set; }//四参数重载只支持查询

2.4 多字段关系映射

支持多个字段关联 5.1.4.108-preview32 (可以是N个)

cs 复制代码
var list=db.Queryable<UnitAddress011>().Includes(x => x.Persons).ToList();
   
//m是主表字段 c是子表字段 是一个json数组 格式不要错了 
[Navigate(NavigateType.Dynamic, "[{m:\"Id\",c:\"AddressId\"},{m:\"Id2\",c:\"AddressId2\"}]")]
public List<UnitPerson011> Persons { get; set; }

💥注意:该功能只能用在查询上,能用正常导航就尽量使用正常导航

2.5 多级导航

配置好实体类,我们可以多级查询(一对多、一对多、多对多都支持只要配好类就可以使用)

cs 复制代码
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int StudentId { get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
    [Navigate(NavigateType.OneToOne, nameof(SchoolId))]//一对一
    public SchoolA SchoolA { get; set; }
    [Navigate(NavigateType.OneToMany, nameof(BookA.studenId))]//一对多
    public List<BookA> Books { get; set; }//只能是null不能赋默认值
 
}
public class SchoolA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int SchoolId { get; set; }
    public string SchoolName { get; set; }
    [Navigate(NavigateType.OneToMany, nameof(RoomA.SchoolId))]//一对多
    public List<RoomA> RoomList { get; set; }//只能是null不能赋默认值
}
 
public class RoomA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int RoomId { get; set; }
    public string RoomName { get; set; }
    public int SchoolId { get; set; }
}
public class BookA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int BookId { get; set; }
 
    public string Name { get; set; }
    public int studenId { get; set; }
}       
 
var list2 = db.Queryable<StudentA>()
             //查2层
             .Includes(st => st.SchoolA, sch=> sch.RoomList)//查询2级(等于EF ThenInclude)
             //查1层
             .Includes(st=> st.Books)  
             .ToList()
//说明: 一对多 多对多 一对多 只要配好了都可以多层级使用
  
              
//如果想超过3个层级需要.AsNavQueryable()
//缺点VS提示会消失,直接写不要在乎意提示不出来,VS关掉在开就行了,只要不改这个代码提示就不会有问题
db.Queryable<Order>()
    Includes(it=>it.xx)
    .AsNavQueryable()//加这个前面
    .Includes(it=>it.1,it=>it.2,it=>it.3,it=>it.4,it=>it.5..)
//.AsNavQueryable()能不用尽量不要用,正常Includes(+3)重载完全够用了

2.6 性能优化

1、升级 如果搜索不到勾选预览版本

5.0.8.1 + 版本针对大数据导航有了很好的性能优化

5.1.4.159 +又进行了一次优化 ,主表一次查一万以上建议升级

2、老版本优化方案

底层分批量查询 适合一次性查询 1000条以上的导航

cs 复制代码
    var list = new List<Tree1>();
 
    db.Queryable<Tree1>()
        .Includes(it => it.Child)
        .ForEach(it => list.Add(it), 300); //每次查询300条

3、关联字段推荐用主键,如果非主键导航加索引为佳

2.7 转DTO (必学的技巧)

1. 自动DTO (推荐 )

cs 复制代码
//Mapster 工具映射 (推荐) 比AutoMapper方便不需要配置
//Nuget直接安装就行了
 
//简单示例:结构一样直接转换
var list=db.Queryable<StudentA>()
           .Includes(x => x.Books).ToList();
var dtoList=list.Adapt<List<StudentDTO>>()
 
 
//技巧示例:这个用法必学通过规则映射DTO
 public class TreeDTO
 {
      public int Id { get; set; }
      public string Name { get; set; }
      public int ParentId { get; set; }
      public string ParentName { get; set; }//对应Parent中的Name
 }
public class Tree
 {
    [SqlSugar.SugarColumn(IsPrimaryKey = true)]
     public int Id { get; set; }
     public string Name { get; set; }
     public int ParentId { get; set; }
     [Navigate(NavigateType.OneToOne,nameof(ParentId))]
     public Tree Parent { get; set; } 
}
         
 var list= db.Queryable<Tree>()
                .Includes(it => it.Parent) 
                .ToList();
 //DTO和List不能是同一个类不然这种映射会失效
 var dtolist= list.Adapt<List<TreeDTO>>();//DTO中的ParentName就有值了

2. 手动转DTO 升级: 5.1.4.71

老版本注意:是 Select 中用导航对象

cs 复制代码
//简单的用法   5.1.4.71
var list = db.Queryable<Student_004>()
        .Includes(x => x.books)
        .Select(x => new Student_004DTO
           {
             books = x.books 
              
            }, true)//true是自动映射其他属性,匿名对象需要手动
           .ToList();
                  
                 
//Mapster转换  5.1.4.71
var list = db.Queryable<Student_004>()
        .Includes(x => x.books)
        .Select(x => new Student_004DTO
         {
           name=x.Name,
           books = x.books.Adapt<List<BooksDTO>>() //导航对象用 Mapster转换 (NUGET安装)
         })
        .ToList();            
 
//DTO中用方法  5.1.4.71
var list = db.Queryable<Student_004>()
         .Includes(x => x.books)
         .Select(x => new Student_004DTO
                 {
                   name=x.Name, 
                   //导航对象books可以是C#任何方法结尾
                   bookIds=x.books.Select(it=>it.id).ToList(), 
                   booksDto=x.books.Select(it=>new BookDTO()
                                       {  id=it.Id,
                                           Name=it.Name  
                                          }).ToList()
                 })
                .ToList();   
 
//联表查询用DTO写法  5.1.4.71           
var list5= db.Queryable<Student_004>()
           .Includes(x => x.school_001, x => x.rooms)
           .Includes(x => x.books)
           .LeftJoin<Order>((x, y) => x.Id==y.sid)
           .Select((x,y) => new Student_004DTO
           {
               SchoolId = x.SchoolId,
               books = x.books,
               school_001 = x.school_001,
               Name=y.Name
           })
           .ToList();

2.8 导航方法

一对多和多对多

在我们一对多和多对多对象我们可以用导航方法 Any() 和导航方法 Count

cs 复制代码
//注意:不需 Includes 就可以使用
Where(it=>it.导航对象.Any())
Where(it=>it.导航对象.Any(z=>z.id==1))
Where(it=>it..导航对象.Any(List<IConditionalModel>)//5.1 
 
//Count用法类似

一对一函数 5.1.2.9

cs 复制代码
//注意:不需 Includes 就可以使用
Where(x=>SqlFunc.Exists(x.SchoolA.Id))//查询存在一对一的主表数据
Where(x=>SqlFunc.Exists(x.SchoolA.Id,List<IConditionalModel>))//查询存在一对一的主表数据

2.9 2个同级 Root->books->[A,B]

如果 Books下面有2个导航 A 和 B

cs 复制代码
//自动写法,Books下面的A和B都会查询出来
.IncludesAllSecondLayer(x=>x.Books)  //自动只能有这么多层次,更深层级需要手动写法
 
//手动写法
.Includes(x => x.Books,x=>x.A) 
.Includes(x => x.Books,x=>x.B)

3、支持联表的导航

3.1.1简单联表导航

cs 复制代码
//联表查询用DTO写法  5.1.4.71           
var list5= db.Queryable<Student_004>()
           .Includes(x => x.school_001, x => x.rooms)
           .Includes(x => x.books)
           .LeftJoin<Order>((x, y) => x.Id==y.sid)
           .Select((x,y) => new Student_004DTO
           {
               SchoolId = x.SchoolId,
               books = x.books,
               school_001 = x.school_001,
               Name=y.Name
           })
           .ToList();

手动映射适合没有主键或者复杂的一些操作,该功能和Includes文档 2.4比较接近

4、特殊层级处理

4.1 创建数据

创建类

cs 复制代码
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int StudentId { get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
    [SugarColumn(IsIgnore = true)]
    public SchoolA SchoolA { get; set; }
}
 
public class SchoolA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int SchoolId { get; set; }
    public string SchoolName { get; set; }
    [SugarColumn(IsIgnore = true)]
    public List<RoomA> RoomList { get; set; }
    [SugarColumn(IsIgnore = true)]
    public List<TeacherA> TeacherList { get; set; }
}
public class TeacherA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int Id { get; set; }
    public int SchoolId { get; set; }
    public string Name { get; set; }
}
public class RoomA
{
    [SugarColumn(IsPrimaryKey = true)]
    public int RoomId { get; set; }
    public string RoomName { get; set; }
    public int SchoolId { get; set; }
}

创建测试数据

cs 复制代码
db.CodeFirst.InitTables<StudentA, RoomA, SchoolA,TeacherA>();
db.DbMaintenance.TruncateTable<StudentA>();
db.DbMaintenance.TruncateTable<RoomA>();
db.DbMaintenance.TruncateTable<SchoolA>();
db.DbMaintenance.TruncateTable<TeacherA>();
db.Insertable(new RoomA() { RoomId = 1, RoomName = "北大001室", SchoolId = 1 }).ExecuteCommand();
db.Insertable(new RoomA() { RoomId = 2, RoomName = "北大002室", SchoolId = 1 }).ExecuteCommand();
db.Insertable(new RoomA() { RoomId = 3, RoomName = "北大003室", SchoolId = 1 }).ExecuteCommand();
db.Insertable(new RoomA() { RoomId = 4, RoomName = "清华001厅", SchoolId = 2 }).ExecuteCommand();
db.Insertable(new RoomA() { RoomId = 5, RoomName = "清华002厅", SchoolId = 2 }).ExecuteCommand();
db.Insertable(new RoomA() { RoomId = 6, RoomName = "清华003厅", SchoolId = 2 }).ExecuteCommand();
 
 
db.Insertable(new SchoolA() { SchoolId = 1, SchoolName = "北大" }).ExecuteCommand();
db.Insertable(new SchoolA() { SchoolId = 2, SchoolName = "清华" }).ExecuteCommand();
 
db.Insertable(new StudentA() { StudentId = 1, SchoolId = 1, Name = "北大jack" }).ExecuteCommand();
db.Insertable(new StudentA() { StudentId = 2, SchoolId = 1, Name = "北大tom" }).ExecuteCommand();
db.Insertable(new StudentA() { StudentId = 3, SchoolId = 2, Name = "清华jack" }).ExecuteCommand();
db.Insertable(new StudentA() { StudentId = 4, SchoolId = 2, Name = "清华tom" }).ExecuteCommand();
 
db.Insertable(new TeacherA() {  SchoolId=1, Id=1, Name="北大老师01" }).ExecuteCommand();
db.Insertable(new TeacherA() { SchoolId = 1, Id =2, Name = "北大老师02" }).ExecuteCommand();
 
db.Insertable(new TeacherA() { SchoolId = 2, Id = 3, Name = "清华老师01" }).ExecuteCommand();
db.Insertable(new TeacherA() { SchoolId = 2, Id = 4, Name = "清华老师02" }).ExecuteCommand();

4.2 手动实现二层

注意:普通导航看标题2 , ThenMapper 是用来处理 普通导航不能实现的功能

结构: Student->SchoolA

cs 复制代码
var list = db.Queryable<StudentA>().ToList();//这儿也可以联表查询
db.ThenMapper(list, stu =>
{
  //如果加Where不能带有stu参数,stu参数写到 SetContext
  //可以用Where写SetContext但是不能带有stu对象
  stu.SchoolA=db.Queryable<SchoolA>().SetContext(scl=>scl.SchoolId,()=>stu.SchoolId,stu).FirstOrDefault();
   
  //可以联查询的
  //stu.xxxx=db.Queryable<SchoolA>().LeftJoin<XXX>().Select(xxxx).SetContext(....).ToList();
});
// SetContext不会生成循环操作,高性能  和直接Where性能是不一样的

注意:1、如果没有 SetContext 那么这个查询将会循环

2、 db.ConextId 外面和里面需要是同一个

4.3 联表导航多层级

注意:普通导航看标题2, ThenMapper 是用来处理 普通导航不能实现的功能

了解原理后我们用 ThenMapper 想映射哪层就映射哪层

cs 复制代码
var treeRoot=db.Queryable<Tree>().Where(it => it.Id == 1).ToList();
//第一层
db.ThenMapper(treeRoot, item =>
{
    item.Child = db.Queryable<Tree>().SetContext(x => x.ParentId, () => item.Id, item).ToList();
});
//第二层
db.ThenMapper(treeRoot.SelectMany(it=>it.Child), it =>
{
    it.Child = db.Queryable<Tree>().SetContext(x => x.ParentId, () => it.Id, it).ToList();
});
//第三层
db.ThenMapper(treeRoot.SelectMany(it => it.Child).SelectMany(it=>it.Child), it =>
{
    it.Child = db.Queryable<Tree>().SetContext(x => x.ParentId, () => it.Id, it).ToList();
});
//这儿只是用树型结构来证明可以实现无限级别导航查询 ,实际开发中树型结构用ToTree实现
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; }
}
// SetContext不会生成循环操作,高性能  和直接Where性能是不一样的

新功能 : 请升级到5.0.6.7 预览版本 及以上

5、树型查询

后续专门章节介绍

6、不加特性使用导航

通过实体 AOP 方法实现,具体用法看实体配置

cs 复制代码
EntityService= (type, columnInfo) =>
{
   p.IfTable<Order>().OneToOne(it => it.Item, nameof(Order.ItemId));
}

7、自动Include 5.1.4.63

第二层的所有导航自动 Include (不支持第三层和第四层)

cs 复制代码
var list3 = db.Queryable<UnitaStudentA>()
              .IncludesAllFirstLayer().ToList();//有重载可以排除不想要的
               
               //排除说明:
               //IncludesAllFirstLayer(nameof(UnitaStudentA.ProjectPhases)) 
               //这样就是排除ProjectPhases的导航属性
               //可以排除多个
               //IncludesAllFirstLayer("a","b") 
               
//自动导航如果有重复的情况: 谁在前面执行哪个
var list3 = db.Queryable<UnitaStudentA>()
              .Includes(it=>it.Order.Where(s=>s.id==1).ToList())
              .IncludesAllFirstLayer().ToList();//自动导航和Order重复
               
//根据名字导航              
db.Queryable<Order>()
//等同于Includes(it=>it.ProjectPhases)
.IncludesByNameString(nameof(Order.ProjectPhases)).ToList()

可以看下图 自动导航替换了下面注释代码

注意:

第一层it下面的通过 IncludesAllFirstLayer 全自动

第二层 (it.ProjectTransferDocs) 通过 IncludesAllSecondLayer 半自动。三层四级需要全部手动

9、兼容EF CORE 非List<T>的导航

cs 复制代码
 vra list=db.Queryable<Order>()
               .Includes(it=>it.导航对象.ToList())//通过.ToList()转成SqlSugar导航类型就行
               .ToList();

10、泛型导航

通过鉴别器实现

cs 复制代码
var dis=db.Queryable<UnitTestDis<Cat>>()
                .Includes(x => x.Animals).ToList();//T是Cat那么就能导航Cat
                  
var dis2 = db.Queryable<UnitTestDis<Dog>>()
               .Includes(x => x.Animals).ToList();//T是Dog那么就能导航Dog

.NET开源 ORM 框架 SqlSugar 系列

  1. 【开篇】.NET开源 ORM 框架 SqlSugar 系列
  2. 【入门必看】.NET开源 ORM 框架 SqlSugar 系列
  3. 【实体配置】.NET开源 ORM 框架 SqlSugar 系列
  4. 【Db First】.NET开源 ORM 框架 SqlSugar 系列
  5. 【Code First】.NET开源 ORM 框架 SqlSugar 系列
  6. 【数据事务】.NET开源 ORM 框架 SqlSugar 系列
  7. 【连接池】.NET开源 ORM 框架 SqlSugar 系列
  8. 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
  9. 【查询基础】.NET开源 ORM 框架 SqlSugar 系列
  10. 【排序用法】.NET开源 ORM 框架 SqlSugar 系列
  11. 【分组去重】.NET开源 ORM 框架 SqlSugar 系列
  12. 【联表查询】.NET开源 ORM 框架 SqlSugar 系列
  13. 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
  14. 【子查询】.NET开源 ORM 框架 SqlSugar 系列
  15. 【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列
相关推荐
老王笔记22 分钟前
MySQL如何区分幻读和不可重复读
数据库·mysql
不爱学习的啊Biao23 分钟前
【08】MySQL复杂查询:子查询语句详解与示例
数据库·mysql·子查询
st_3329 分钟前
Junit5 单元测试入门
数据库·单元测试·log4j
s***g54031 分钟前
MySQL-操作数据库备份与恢复
数据库·mysql
CQU_JIAKE1 小时前
11.5【算法】6-1 表彰优秀学生(多态)
数据库
Elastic 中国社区官方博客2 小时前
使用数据层进行数据生命周期管理
大数据·数据库·elasticsearch·搜索引擎·全文检索·时序数据库
我爱李星璇2 小时前
Spring Boot项目的创建
java·数据库·spring boot
锵锵锵锵~蒋2 小时前
实时数据开发|Flink异步IO--提升性能和吞吐量
jvm·数据库·flink·实时数据开发
小麦项目管理指南3 小时前
工程企业需要什么样的财务软件?
大数据·数据库·信息可视化·项目管理
涛思数据(TDengine)3 小时前
解密时序数据库的未来:TDengine Open Day技术沙龙精彩回顾
数据库·时序数据库·tdengine