企业网站是怎么建站的,有什么网站可以自己做书,微搭低代码平台,搭建公司.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 系列【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 listdb.QueryableTest().Includes(t t.Provinces, propro.Citys ,citcit.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),typesex)]//具体用法可以看配置查询 https://www.donet5.com/Home/Doc?typeId2309}
public class SchoolA
{[SugarColumn(IsPrimaryKey true, IsIdentity true)]public int Id{ get; set; }public string SchoolName { get; set; }
} //导航主表过滤 导航属性过滤
var list db.QueryableStudentA().Includes(x x.SchoolA) //填充子对象 不填充可以不写.Where(x x.SchoolA.SchoolName北大) .ToList();//导航主表过滤 只查有导航数据 新功能5.1.2.8
var list db.QueryableStudentA().Includes(x x.SchoolA) //填充子对象 不填充可以不写.Where(x SqlFunc.Exists(x.SchoolA.主键)).ToList(); //导航子表过滤 5.0.9.4-preview06 请注意升级
//创建一个扩展函数默认是Class不支持Where
public static ListT WhereT(this T thisValue, FuncT,bool whereExpression ) where T:class,new()
{return new ListT() { thisValue };
}
var list db.QueryableStudent_003().Includes(x x.school_001.Where(zz.Namea).ToList())//扩展的Where对子表进行过滤.ToList(); //5.0.9.4-preview06 才支持 请注意升级 请注意升级//导航 指定字段 5.1.3.38
var list db.QueryableStudentA().Includes(x x.SchoolA.ToList(itnew SchoolA(){ Name it.Name,idit.Id})) .ToList(); //只查一个字段写法1
var list db.QueryableStudentA().Where(x x.id1) //Where和Select中别名要写一样.Select(x new { xx,SchoolName x.SchoolA.SchoolName}).ToList();//只查一个字段写法2
[Navigate(NavigateType.OneToOne, nameof(SchoolId))]
public SchoolA SchoolA { get; set; }
[SugarColumn(IsIgnoretrue)]//加IsIgnore
public string SchoolName{getthis.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表中的studenIdpublic ListBookA Books { get; set; }//注意禁止给books手动赋值//用例2:反向导航支持StudentA没有主键或者指定关系[Navigate(NavigateType.OneToMany, nameof(BookA.studenId),nameof(Id))] public ListBookA 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.QueryableStudentA()
.Includes(x x.Books)
.ToList();//例2支持Any和Count 对主表进行过滤 (子对象过滤看下面)
var list db.QueryableStudentA()
.Includes(x x.Books)
.Where(x x.Books.Any())
//带条件的
//.Where(x x.Books.Any(zz.Namejack)))
.ToList();//例3: 没有Includes也可以使用过滤
var list2 db.QueryableStudentA()
.Where(x x.Books.Any())//Any中可以加条件 Any(zz.BookId1)
.ToList(); //例4 Where子对象进行排序和过滤 (支持WhereIF)
var list db.QueryableStudentA().Includes(x x.Books.Where(y y.BookId 0).OrderBy(y y.BookId).ToList()).ToList();//例5 主表子表都过滤
var list db.QueryableStudentA()
.Includes(x x.Books.Where(itit.Namejack).ToList())//只过滤子表
.Where(x x.Books.Any(zz.Namejack)))//通过子表过滤主表
.ToList();//例6Select指定字段
var list db.QueryableStudentA().Includes(x x.Books.Select(znew BookA() { Names z.Names }).ToList()) //例7Select多层级 (结构StudentAt-books-BookItems)
var list db.QueryableStudentA().Includes(x x.Books.Select(znew BookA(){Namesz.Name}.ToList(),itBookItems)) .ToList();、//Includes中的Select只能是字段 不能导航对象 //例8OrderBy指定字段 Skip Take可以分页
var list db.QueryableStudentA().Includes(x x.Books.OrderBy(zz.Id).ToList()) .ToList();//例9Take取前几条
var list db.QueryableStudentA().Includes(x x.Books.Take(10).ToList()) .ToList(); //例10DTO支持进行了强化
看标题2.7 //例11一对多后还可用追加字段映射MappingField 如果以前是1个字关联现在追加后就成了11
db.QueryableStudentA().Includes(x x.Books.MappingField(zz.字段,()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 ListB1 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 ListA1 AList { get; set; }//只能是null不能赋默认值
}
//例1:简单用法 直接填充B的集合只要配置好特性非常简单
var list3 db.QueryableA1().Includes(x x.BList).ToList(); //例2:支持子对象排序和过滤 (支持WhereIF)
var list3 db.QueryableA1().Includes(x x.BList.Where(zz.Id0).ToList()).ToList(); //例3:支持主表过滤 Any和Count
var list3 db.QueryableA1().Includes(x x.BList).Where(xx.BList.Any())//Any里面可以加条件 Any(zz.xxxx0).ToList();//例4主表子表都过滤
var list db.QueryableStudentA().Includes(x x.BList.Where(itit.Namejack).ToList())//只过滤子表.Where(x x.BList.Any(zz.Namejack)))//通过子表过滤主表.ToList(); //不使用Includes一样可以过滤
var list3 db.QueryableA1() .Where(xx.BList.Any()) //可以加条件.Where(xx.BList.Any(zz.xxxx.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 ListRole Roles { get; set; }//四参数重载只支持查询 2.4 多字段关系映射
支持多个字段关联 5.1.4.108-preview32 可以是N个 var listdb.QueryableUnitAddress011().Includes(x x.Persons).ToList();//m是主表字段 c是子表字段 是一个json数组 格式不要错了
[Navigate(NavigateType.Dynamic, [{m:\Id\,c:\AddressId\},{m:\Id2\,c:\AddressId2\}])]
public ListUnitPerson011 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 ListBookA 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 ListRoomA 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.QueryableStudentA()//查2层.Includes(st st.SchoolA, sch sch.RoomList)//查询2级(等于EF ThenInclude)//查1层.Includes(st st.Books) .ToList()
//说明: 一对多 多对多 一对多 只要配好了都可以多层级使用//如果想超过3个层级需要.AsNavQueryable()
//缺点VS提示会消失直接写不要在乎意提示不出来VS关掉在开就行了只要不改这个代码提示就不会有问题
db.QueryableOrder()Includes(itit.xx).AsNavQueryable()//加这个前面.Includes(itit.1,itit.2,itit.3,itit.4itit.5..)
//.AsNavQueryable()能不用尽量不要用正常Includes(3)重载完全够用了 2.6 性能优化
1、升级 如果搜索不到勾选预览版本
5.0.8.1 版本针对大数据导航有了很好的性能优化
5.1.4.159 又进行了一次优化 主表一次查一万以上建议升级
2、老版本优化方案
底层分批量查询 适合一次性查询 1000 条以上的导航 var list new ListTree1();db.QueryableTree1().Includes(it it.Child).ForEach(it list.Add(it), 300); //每次查询300条 3、关联字段推荐用主键如果非主键导航加索引为佳
2.7 转DTO (必学的技巧)
1. 自动DTO 推荐 //Mapster 工具映射 (推荐) 比AutoMapper方便不需要配置
//Nuget直接安装就行了//简单示例结构一样直接转换
var listdb.QueryableStudentA().Includes(x x.Books).ToList();
var dtoListlist.AdaptListStudentDTO()//技巧示例这个用法必学通过规则映射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.QueryableTree().Includes(it it.Parent) .ToList();//DTO和List不能是同一个类不然这种映射会失效var dtolist list.AdaptListTreeDTO();//DTO中的ParentName就有值了 2. 手动转DTO 升级 5.1.4.71
老版本注意是 Select 中用导航对象 //简单的用法 5.1.4.71
var list db.QueryableStudent_004().Includes(x x.books).Select(x new Student_004DTO{books x.books }, true)//true是自动映射其他属性匿名对象需要手动.ToList();//Mapster转换 5.1.4.71
var list db.QueryableStudent_004().Includes(x x.books).Select(x new Student_004DTO{namex.Name,books x.books.AdaptListBooksDTO() //导航对象用 Mapster转换 NUGET安装}).ToList(); //DTO中用方法 5.1.4.71
var list db.QueryableStudent_004().Includes(x x.books).Select(x new Student_004DTO{namex.Name, //导航对象books可以是C#任何方法结尾bookIdsx.books.Select(itit.id).ToList(), booksDtox.books.Select(itnew BookDTO(){ idit.Id,Nameit.Name }).ToList()}).ToList(); //联表查询用DTO写法 5.1.4.71
var list5 db.QueryableStudent_004().Includes(x x.school_001, x x.rooms).Includes(x x.books).LeftJoinOrder((x, y) x.Idy.sid).Select((x,y) new Student_004DTO{SchoolId x.SchoolId,books x.books,school_001 x.school_001,Namey.Name}).ToList(); 2.8 导航方法
一对多和多对多
在我们一对多和多对多对象我们可以用导航方法 Any() 和导航方法 Count //注意不需 Includes 就可以使用
Where(itit.导航对象.Any())
Where(itit.导航对象.Any(zz.id1))
Where(itit..导航对象.Any(ListIConditionalModel)//5.1 //Count用法类似 一对一函数 5.1.2.9 //注意不需 Includes 就可以使用
Where(xSqlFunc.Exists(x.SchoolA.Id))//查询存在一对一的主表数据
Where(xSqlFunc.Exists(x.SchoolA.Id,ListIConditionalModel))//查询存在一对一的主表数据 2.9 2个同级 Root-books-[A,B]
如果 Books下面有2个导航 A 和 B //自动写法,Books下面的A和B都会查询出来
.IncludesAllSecondLayer(xx.Books) //自动只能有这么多层次更深层级需要手动写法//手动写法
.Includes(x x.Books,xx.A)
.Includes(x x.Books,xx.B) 3、支持联表的导航
3.1.1简单联表导航 //联表查询用DTO写法 5.1.4.71
var list5 db.QueryableStudent_004().Includes(x x.school_001, x x.rooms).Includes(x x.books).LeftJoinOrder((x, y) x.Idy.sid).Select((x,y) new Student_004DTO{SchoolId x.SchoolId,books x.books,school_001 x.school_001,Namey.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 ListRoomA RoomList { get; set; }[SugarColumn(IsIgnore true)]public ListTeacherA 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.InitTablesStudentA, RoomA, SchoolA,TeacherA();
db.DbMaintenance.TruncateTableStudentA();
db.DbMaintenance.TruncateTableRoomA();
db.DbMaintenance.TruncateTableSchoolA();
db.DbMaintenance.TruncateTableTeacherA();
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() { SchoolId1, Id1, 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.QueryableStudentA().ToList();//这儿也可以联表查询
db.ThenMapper(list, stu
{//如果加Where不能带有stu参数stu参数写到 SetContext//可以用Where写SetContext但是不能带有stu对象stu.SchoolAdb.QueryableSchoolA().SetContext(sclscl.SchoolId,()stu.SchoolId,stu).FirstOrDefault();//可以联查询的//stu.xxxxdb.QueryableSchoolA().LeftJoinXXX().Select(xxxx).SetContext(....).ToList();
});
// SetContext不会生成循环操作高性能 和直接Where性能是不一样的 注意1、如果没有 SetContext 那么这个查询将会循环 2、 db.ConextId 外面和里面需要是同一个
4.3 联表导航多层级
注意普通导航看标题2 ThenMapper 是用来处理 普通导航不能实现的功能
了解原理后我们用 ThenMapper 想映射哪层就映射哪层 var treeRootdb.QueryableTree().Where(it it.Id 1).ToList();
//第一层
db.ThenMapper(treeRoot, item
{item.Child db.QueryableTree().SetContext(x x.ParentId, () item.Id, item).ToList();
});
//第二层
db.ThenMapper(treeRoot.SelectMany(itit.Child), it
{it.Child db.QueryableTree().SetContext(x x.ParentId, () it.Id, it).ToList();
});
//第三层
db.ThenMapper(treeRoot.SelectMany(it it.Child).SelectMany(itit.Child), it
{it.Child db.QueryableTree().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 ListTree Child { get; set; }
}
// SetContext不会生成循环操作高性能 和直接Where性能是不一样的 新功能 请升级到5.0.6.7 预览版本 及以上
5、树型查询
后续专门章节介绍
6、不加特性使用导航
通过实体 AOP 方法实现具体用法看实体配置 EntityService (type, columnInfo)
{p.IfTableOrder().OneToOne(it it.Item, nameof(Order.ItemId));
} 7、自动Include 5.1.4.63
第二层的所有导航自动 Include (不支持第三层和第四层) var list3 db.QueryableUnitaStudentA().IncludesAllFirstLayer().ToList();//有重载可以排除不想要的//排除说明//IncludesAllFirstLayer(nameof(UnitaStudentA.ProjectPhases)) //这样就是排除ProjectPhases的导航属性//可以排除多个//IncludesAllFirstLayer(a,b) //自动导航如果有重复的情况: 谁在前面执行哪个
var list3 db.QueryableUnitaStudentA().Includes(itit.Order.Where(ss.id1).ToList()).IncludesAllFirstLayer().ToList();//自动导航和Order重复//根据名字导航
db.QueryableOrder()
//等同于Includes(itit.ProjectPhases)
.IncludesByNameString(nameof(Order.ProjectPhases)).ToList() 可以看下图 自动导航替换了下面注释代码 注意
第一层it下面的通过 IncludesAllFirstLayer 全自动
第二层 (it.ProjectTransferDocs) 通过 IncludesAllSecondLayer 半自动。三层四级需要全部手动
9、兼容EF CORE 非ListT的导航 vra listdb.QueryableOrder().Includes(itit.导航对象.ToList())//通过.ToList()转成SqlSugar导航类型就行.ToList(); 10、泛型导航
通过鉴别器实现 var disdb.QueryableUnitTestDisCat().Includes(x x.Animals).ToList();//T是Cat那么就能导航Catvar dis2 db.QueryableUnitTestDisDog().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 系列