ORM核心功能之导航属性- EFCore和 SqlSugar
导航属性
导航属性是作为ORM核心功能中的核心,在SqlSugar没有支持导航属性前,都说只是一个高级DbHelper, 经过3年的SqlSugar重构已经拥有了一套
非常成熟的导航属性体系,本文不是重点讲SqlSugar而是重点讲导航属性的作用,让更多写Sql人还未使用ORM的人了解到ORM的作用。
1.复杂的查询过滤
用户根据权限过滤,用户根据组织过滤 等这种多对多情况用SQL就相当复杂 ,例如:用SQL写一个多对多过滤就要联3个表(主表 中间表 从表),如果
Where中用到多个多对多或者嵌套多对多那写SQL简直就是恶梦 (一对多和一对一差也有提升并,没有多对多明显)
//EF CORE查询
var Persons= dbContext.Person //需要定义DbSet才能点出来
.Where(it=>it.Files.Any(y=>y.ChildFiles.Any(s=>s.name=="A"))).ToList() //SqlSugar 查询
var Persons= dbContext.Queryable<Person>()
.Where(it=>it.Files.Any(y=>y.ChildFiles.Any(s=>s.name=="A"))).ToList()
用SQL写如下:
SELECT p.*
FROM Person p
WHERE EXISTS (
SELECT 1
FROM PersonFile pf
INNER JOIN File f ON pf.FileId = f.FileId
INNER JOIN PersonFile pf2 ON f.FileId = pf2.FileId
WHERE pf.PersonId = p.PersonId
AND pf2.PersonId IN (
SELECT p2.PersonId
FROM Person p2
INNER JOIN PersonFile pf3 ON p2.PersonId = pf3.PersonId
INNER JOIN File f2 ON pf3.FileId = f2.FileId
WHERE f2.name = 'A'
)
)
像SAAS系统这种多对多用的非常多,特别在组织、用户、角色、文件等无处理不在,这也是为什么要用ORM的原因
2.复杂的表单提交
如果您的人事管理需要包含更多的信息,例如学历和工作经验等字段,您可以在代码中添加相应的实体和关联。
假设您有以下实体:人员(Person)、部门(Department)、职位(Position)、学历(Education)和工作经验(WorkExperience)。
var person = new Person
{
// 设置人员属性...
Department = new Department
{
// 设置部门属性...
},
Position = new Position
{
// 设置职位属性...
},
Education = new Education
{
// 设置教育属性...
},
WorkExperience = new WorkExperience
{
// 设置工作经历属性...
}
};
代码如下:
//SqlSugar 导航插入
db.InsertNav(person)
.Include(z1 => z1.Department)
.Include(z1 => z1.Position)
.Include(z1 => z1.Education)
.Include(z1 => z1.WorkExperience)
.ExecuteCommand();//导航插入 一句就能搞定,先插入主表,然后在根据主表的主键在插入从表,特别是自增列用导航代码清爽很多
3.多层级结构的查询
因为Sql本身就不支持对多层级结构查询,所以不用ORM想实现高性能的多层级结构是需要花大量精力去优化和写代码的
//EF CORE查询
var Persons= dbContext.Person
.Include(z1 => z1.Department)
.Include(z1 => z1.Position)
.Include(z1 => z1.Education)
.Include(z1 => z1.WorkExperience).ToList()
EF Core导航属性配置
EF多对多
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
// 其他学生属性... public virtual ICollection<Course> Courses { get; set; }
} public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
// 其他课程属性... public virtual ICollection<Student> Students { get; set; }
} public class StudentCourse
{
public int CourseId { get; set; }
public int StudentId { get; set; } }
// 配置多对多关系
protected override void OnModelCreating(ModelBuilder modelBuilder)
{ modelBuilder.Entity<Student>()
.HasMany(s => s.Courses)
.WithMany(c => c.Students) .UsingEntity(j => j.ToTable("StudentCourse"));
}
EF一对多和一对一
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
// 其他部门属性... public virtual ICollection<Employee> Employees { get; set; }
} public class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
// 其他员工属性... public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
} // 配置一对多关系
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>()
.HasMany(d => d.Employees)
.WithOne(e => e.Department)
.HasForeignKey(e => e.DepartmentId);
}
SqlSugar导航属性配置
SqlSugar多对多
//实体
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; }
[Navigat(typeof(ABMapping1), nameof(ABMapping1.BId), nameof(ABMapping1.AId))]//注意顺序
public List<A1> AList { get; set; }//只能是null不能赋默认值
}
Sqlugar一对一和一对多
//实体
public class StudentA
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int StudentId { get; set; }
public string Name { get; set; }public int SchoolId { get; set; }
[Navigate(NavigateType.OneToOne, nameof(SchoolId))]//一对一 SchoolId是StudentA类里面的
public SchoolA SchoolA { get; set; } //不能赋值只能是null
}
public class SchoolA
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id{ get; set; }
public string SchoolName { get; set; }
[Navigate(NavigateType.OneToMany, nameof(BookA.studenId))]//一对多 BookA表中的studenId
public List<BookA> Books { get; set; }//注意禁止给books手动赋值 }
SqlSugar 2023年导航新功能
SqlSugar 第一层自动导航
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()
SqlSugar第二层半自动
//自动写法,Books下面的A和B都会查询出来
.IncludesAllSecondLayer(x=>x.Books) //自动只能有这么多层次,更深层级需要手动写法 //手动写法
.Includes(x => x.Books,x=>x.A)
.Includes(x => x.Books,x=>x.B)
SqlSugar导航DTO转换
在前二年SqlSugar导航只能说够用,并不算好用,今年重点将导航DTO进行了强化
//简单的用法 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,
//可以是C#任何方法结尾
//比如 b.books.FirstOrDefault() (因为是C#方法First没有值会报错)
bookIds=x.books.Select(it=>it.id).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();
当你遇到繁琐的数据库操作时,SQLSugar就像是一双温暖的手,帮你轻松解决难题。它是一个强大的工具,让你的数据库管理变得更简单、更高效。下载SQLSugar吧,让它成为你的数据之路上的得力助手,让你的编程之旅充满感动与喜悦!
原码下载: https://github.com/DotNetNext/SqlSugar
总结:
无论是EF CORE还是SQLSUGAR 使用了导航属性都不再需要费心写繁琐的SQL语句,只需简单地调用导航属性,便能轻松获取所需的数据。让我们一起追随这份感动,选择使用导航属性,让编程的旅途更加愉悦,让代码的世界充满美好与便捷!
ORM核心功能之导航属性- EFCore和 SqlSugar的更多相关文章
- FreeSql 导航属性的联级保存功能
写在前面 FreeSql 一个款 .net 平台下支持 .net framework 4.5+..net core 2.1+ 的开源 ORM.单元测试超过3100+,正在不断吸引新的开发者,生命不息开 ...
- .NET ORM 导航属性【到底】可以解决什么问题?
写在开头 从最早期入门时的单表操作, 到后来接触了 left join.right join.inner join 查询, 因为经费有限,需要不断在多表查询中折腾解决实际需求,不知道是否有过这样的经历 ...
- Xwork概况 XWork是一个标准的Command模式实现,并且完全从web层脱离出来。Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式语言(OGNL – the Object Graph NavigationLanguage),IoC(Inversion of Control反转控制)容器等。 ----------------
Xwork概况 XWork是一个标准的Command模式实现,并且完全从web层脱离出来.Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式 ...
- ASP.NET EF 延迟加载,导航属性延迟加载
ASP.NET EF 延迟加载,导航属性延迟加载 EF(EntityFramework)原理:属于ORM的一种实现 通过edmx文件来查看三部分:概念模型,数据模型,映射关系,上下文DbConte ...
- ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪
ASP.NET MVC深入浅出(被替换) 一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- Spring 核心功能演示
Spring 核心功能演示 Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot, ...
- EF Core 三 、 骚操作 (导航属性,内存查询...)
EF Core 高阶操作 本文之前,大家已经阅读了前面的系列文档,对其有了大概的了解 我们来看下EF Core中的一些常见高阶操作,来丰富我们业务实现,从而拥有更多的实现选择 1.EF 内存查找 wh ...
- 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11 测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...
- 带连接池的netty客户端核心功能实现剖解
带连接池的netty客户端核心功能实现剖析 带连接池的netty的客户端核心功能实现剖析 本文为原创,转载请注明出处 源码地址: https://github.com/zhangxianwu/ligh ...
随机推荐
- java多线程--5 同步方法和同步块synchronized
java多线程--5 同步方法和同步块synchronized 同步方法和同步块 同步方法:关键字synchronized,包括synchronized方法和synchronized块 public ...
- noopener, noreferrer 及 nofollow 的用法
<a> 标签通常会配合着使用 noopener, noreferrer 及 nofollow 这些属性, 它们的作用及用法如下. noopener 当给链接加上 target=" ...
- OSM(OpenStreetMap)全球路网数据下载方式介绍
本文对OpenStreetMap(OSM)网页与各类OSM数据的多种下载方式加以详细介绍,并对不同数据下载方式加以对比. OSM数据包含道路与铁路路网.建筑.水体.土地利用.兴趣点.行政区边界 ...
- ECC(SM2) 简介及 C# 和 js 实现【加密知多少系列】
〇.简介 椭圆曲线密码学(Elliptic curve cryptography:ECC),一种建立公开密钥加密的演算法,基于椭圆曲线数学.利用有限域上椭圆曲线的点构成的 Abel 群离散对数难解性, ...
- ACM-学习记录-素数筛
前言 近期发现我NEFU低年级组校赛题目只有模拟+数论,恰恰都是我最不会做的,数论方面反反复复用到的就是素数筛,特在此记录一下,闲来无事自己翻阅当作复习复习,以免被到时候一道题都做不出来菜到巨佬们. ...
- .NET Core MongoDB数据仓储和工作单元模式实操
前言 上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操.如:获取所有用户信息.获取用户分页数据.通过用户ID获取对应用户信息.添加 ...
- Java线程池浅析
1. 什么是线程池?我们为什么需要线程池? 线程池即可以存放线程的容器,若干个可执行现成在"容器"中等待被调度. 我们都知道,线程的生命周期中有以下状态:新建状态(New).就绪状 ...
- 上传了ipa但在苹果App Store中没有看到构建版本的问题
AU上传ipa出现下图红框提示说明成功上传,但有时App Store后台没有出现构建版本,请查看下面详细说明! 编辑 一.首先登录iTunes Connect 后台.查看ipa构建情况 http ...
- 一文讲透产品经理如何用好ChatGPT
作者:京东零售 何雨航 "4.0版本的ChatGPT可以有效提升产品经理工作效率,但并无法替代产品经理的角色." 一.引言 3月15日,OpenAI发布了最新的基于GPT-4的Ch ...
- flink之Sink to MySQL和Redis
前言 下面这篇文章是使用Flink的Sink 写出数据到Redis和MySQL Flink之Sink写入Redis和MySQL Flink需要添加Sink的时候,需要自己去添加写Sink,我们可以实现 ...