【导航查询】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列
- 【开篇】.NET开源 ORM 框架 SqlSugar 系列
- 【入门必看】.NET开源 ORM 框架 SqlSugar 系列
- 【实体配置】.NET开源 ORM 框架 SqlSugar 系列
- 【Db First】.NET开源 ORM 框架 SqlSugar 系列
- 【Code First】.NET开源 ORM 框架 SqlSugar 系列
- 【数据事务】.NET开源 ORM 框架 SqlSugar 系列
- 【连接池】.NET开源 ORM 框架 SqlSugar 系列
- 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
- 【查询基础】.NET开源 ORM 框架 SqlSugar 系列
- 【排序用法】.NET开源 ORM 框架 SqlSugar 系列
- 【分组去重】.NET开源 ORM 框架 SqlSugar 系列
- 【联表查询】.NET开源 ORM 框架 SqlSugar 系列
- 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
- 【子查询】.NET开源 ORM 框架 SqlSugar 系列
- 【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列
💦万丈高楼平地起,做开发想要技术精进,必须要有扎实的基础功底。基础SQL查询语法一定要牢记于心,才能应对后面更为复杂的形势。
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(子表)中的 studenId 和 StudentA(主表)中的主键关联
//实体
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)
//实体
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个)
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>>()
//技巧示例:这个用法必学通过规则映射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 中用导航对象
//简单的用法 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()
可以看下图 自动导航替换了下面注释代码
注意:
第一层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那么就能导航Cat
var dis2 = db.Queryable<UnitTestDis<Dog>>()
.Includes(x => x.Animals).ToList();//T是Dog那么就能导航Dog
.NET开源 ORM 框架 SqlSugar 系列
- 【开篇】.NET开源 ORM 框架 SqlSugar 系列
- 【入门必看】.NET开源 ORM 框架 SqlSugar 系列
- 【实体配置】.NET开源 ORM 框架 SqlSugar 系列
- 【Db First】.NET开源 ORM 框架 SqlSugar 系列
- 【Code First】.NET开源 ORM 框架 SqlSugar 系列
- 【数据事务】.NET开源 ORM 框架 SqlSugar 系列
- 【连接池】.NET开源 ORM 框架 SqlSugar 系列
- 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
- 【查询基础】.NET开源 ORM 框架 SqlSugar 系列
- 【排序用法】.NET开源 ORM 框架 SqlSugar 系列
- 【分组去重】.NET开源 ORM 框架 SqlSugar 系列
- 【联表查询】.NET开源 ORM 框架 SqlSugar 系列
- 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
- 【子查询】.NET开源 ORM 框架 SqlSugar 系列
- 【嵌套查询】.NET开源 ORM 框架 SqlSugar 系列