【导航查询】.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查询语法一定要牢记于心,才能应对后面更为复杂的形势。

e57c501b379f46dfb38d3b8584575f1f.png​​

1、导航查询特点 

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

1.1 无外键开箱就用

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

1.2 高性能优 

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

 支持大数据分页导航查询

3.3 语法超级爽

 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 )

//实体
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)

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

 //第一个参数:当前表字段 //第二个参数: 子表中字段[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(子表)中的 studenIdStudentA(主表)中的主键关联

//实体
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表中的studenIdpublic 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)

//实体
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), //中间表 aidnameof(OptRole.roleId),//中间表 bidnameof(OperatorInfo.id),//a表 idnameof(Role.id2))] //b表idpublic List<Role> Roles { get; set; }//四参数重载只支持查询

2.4  多字段关系映射

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

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 多级导航

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

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 条以上的导航

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 (推荐 )

//Mapster 工具映射 (推荐) 比AutoMapper方便不需要配置
//Nuget直接安装就行了//简单示例:结构一样直接转换
var list=db.Queryable<StudentA>().Includes(x => x.Books).ToList();
var dtoList=list.Adapt<List<StudentDTO>>()//技巧示例:这个用法必学通过规则映射DTOpublic 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 中用导航对象

//简单的用法   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 

//注意:不需 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

//注意:不需 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

//自动写法,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简单联表导航

//联表查询用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  创建数据

创建类

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; }
}

创建测试数据

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

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 想映射哪层就映射哪层

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 方法实现,具体用法看实体配置

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

7、自动Include 5.1.4.63

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


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()

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

image.png

注意:

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

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

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

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

10、泛型导航

通过鉴别器实现

var dis=db.Queryable<UnitTestDis<Cat>>().Includes(x => x.Animals).ToList();//T是Cat那么就能导航Catvar 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 系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62797.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谷歌浏览器中搜索引擎的设置与管理

谷歌浏览器作为全球最受欢迎的网络浏览器之一&#xff0c;以其高速、稳定和丰富的功能深受用户喜爱。对于许多用户来说&#xff0c;自定义和管理搜索引擎是提升浏览体验的重要一环。本文将详细介绍如何在谷歌浏览器中设置和管理搜索引擎&#xff0c;包括如何修改默认搜索引擎、…

【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程

文章目录 【Linux 篇】Docker 容器星河与镜像灯塔&#xff1a;Linux 系统下解锁应用部署奇幻征程前言一 、docker上部署mysql1. 拉取mysql镜像2. 创建容器3. 远程登录mysql 二 、docker上部署nginx1. 拉取nginx镜像2. 在dockerTar目录下 上传nginx.tar rz命令3. 创建nginx容器4…

vue.js学习(day 18)

实例&#xff1a;面经基础版

XGBoost算法原理

XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是一种基于梯度提升决策树的机器学习算法&#xff0c;它通过优化损失函数来构建模型。XGBoost在许多数据科学竞赛中取得了成功&#xff0c;并且由于其高效性和准确性而广受好评。 1. 梯度提升框架 在开始讨论XGBoost…

vim插件管理器vim-plug替代vim-bundle

文章目录 vim-plug与vim-bundle对比vim-plug安装vim-plug管理安装插件相关文章 vim-plug与vim-bundle对比 vim-plug 和 vim-bundle 都是 Vim 的插件管理器&#xff0c;但它们有一些关键的区别。以下是两者的主要对比&#xff1a; 易用性和简洁性 vim-plug: 易用性: vim-plug …

LeetCode78:子集

链接&#xff1a;78. 子集 假设我们要求[1, 2, 3]的子集&#xff1a; 我们知道[1, 2]的子集是A&#xff1a; 而[1, 2, 3]就是比[1, 2]多了一个元素3&#xff1b;所以将3加入到上述A中的每个集合中&#xff0c;得到一个新集合B&#xff1a; 结论&#xff1a;[1, 2, 3]的子集就…

【k8s】监控metrics-server

metrics-server介绍 Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。Metric server从每个节点上KubeletAPI收集指标&#xff0c;通过Kubernetes聚合器注册在Master APIServer中。为集群提供Node、Pods资源利用率指标。 就像Linux 系统一样…

如何具体实现商品详情的提取?

在电商领域&#xff0c;获取商品详情信息对于市场分析、价格比较、商品推荐等应用场景至关重要。本文将详细介绍如何使用Java编写爬虫程序&#xff0c;以合法合规的方式获取淘宝商品的详情信息&#xff0c;并提供详细的代码示例。 1. 环境准备 在开始编写爬虫之前&#xff0c;…

电子电气架构 --- E/E(电子电气架构)的重新定义

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…

HCIE IGP双栈综合实验

实验拓扑 实验需求及解法 本实验模拟ISP网络结构&#xff0c;R1/2组成国家骨干网&#xff0c;R3/4组成省级网络&#xff0c;R5/6/7组成数据中 心网络。 配置所有ipv4地址&#xff0c;请自行测试直连。 R1 sysname R1 interface GigabitEthernet0/0/0ip address 12.1.1.1 255.…

5、防火墙一

防火墙的含义 firewalld&#xff1a;隔离功能 病毒防护&#xff1a; 1、入侵检测系统&#xff1a;在互联网访问的过程中&#xff0c;不阻断任何网络访问&#xff0c;也不会定位网络的威胁&#xff0c;提供告警和事后的监督&#xff0c;类似于监控。 2、入侵防御系统&#x…

5G学习笔记之随机接入

目录 1. 概述 2. MSG1 2.1 选择SSB 2.2 选择Preamble Index 2.3 选择发送Preamble的时频资源 2.4 确定RA-RNTI 2.5 确定发送功率 3. MSG2 4. MSG3 5. MSG4 6. 其它 6.1 切换中的随机接入 6.2 SI请求的随机接入 6.3 通过PDCCH order重新建立同步 1. 概述 随机接入…

【落羽的落羽 C语言篇】指针·之其五

文章目录 一、冒泡排序二、qsort排序1. qsort使用指南2.回调函数3. qsort函数的模拟实现 一、冒泡排序 冒泡排序的核心思想就是&#xff1a;两两相邻的元素进行比较和交换。 现在&#xff0c;我们想编写一个函数&#xff0c;使它能够运用冒泡排序的原理&#xff0c;由小到大排…

Ajax基础总结(思维导图+二维表)

一些话 刚开始学习Ajax的时候&#xff0c;感觉很模糊&#xff0c;但是好像学什么都是这样的&#xff0c;很正常&#xff0c;但是当你学习的时候要持续性敲代码&#xff0c;边敲代码其实就可以理解很多了。然后在最后的总结&#xff0c;其实做二维表之后&#xff0c;就可以区分…

具有多个表盘、心率传感器、指南针和游戏的 DIY 智能手表

在此&#xff0c;我们将使用所学到的知识&#xff0c;结合使用硬件和软件组件从头开始创建自己的智能手表。在项目的这一部分&#xff0c;您将被指导完成组装硬件组件、设置软件以及配置智能手表的设置和功能的过程。到本项目结束时&#xff0c;您将拥有一款功能齐全的智能手表…

算法魅力之牛叉的前缀和

1.什么是前缀和 前缀和算法&#xff08;Prefix Sum Algorithm&#xff09; 是一种常用的算法技巧&#xff0c;用于快速计算数组的某些子数组的和。它通过提前计算出数组中元素的累加和&#xff0c;来加速后续的区间和查询&#xff0c;特别适用于需要频繁查询子数组和的场景。 …

Java JVM(内存结构,垃圾回收,类加载,内存模型)

一、JVM 主要功能 1. 什么是 jvm&#xff1f; JVM&#xff08;Java Virtual Machine)&#xff1a;负责运行 Java 程序的核心组件。它将 Java 字节码&#xff08;.class 文件&#xff09;解释或编译为机器代码&#xff0c;并提供内存管理、垃圾回收和线程管理等功能。 JRE (J…

机器学习基础之集成学习

集成学习&#xff08;Ensemble Learning&#xff09;是一种强大的机器学习方法&#xff0c;它通过结合多个模型的预测结果来提高整体的学习效果。集成学习方法在许多实际应用中表现出了优秀的性能&#xff0c;尤其在处理复杂问题时&#xff0c;它常常能够比单一模型取得更好的结…

33 基于单片机的智能窗帘控制系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DHT11温湿度传感器检测温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器转换模拟,光敏传感器&#xff0c;采用GP2D12红外传感器&#xff0c;通过LCD1602显示屏显示…

使用docker-compese部署SFTPGo详解

官网&#xff1a;SFTP & FTP as a Managed Service (SaaS) and On-premise 一、SFTPGo简介 SFTPGo 是一款功能强大的文件传输服务器软件。它支持多种协议&#xff08;SFTP、SCP、FTP/S、WebDAV、HTTP/S&#xff09;和多个存储后端。 借助 SFTPGo&#xff0c;您可以利用本地…