查缺补漏系统学习 EF Core 6 - 数据查询

这是 EF Core 系列的第四篇文章,上一篇文章讲述了 EF Core 中的实体迁移与数据播种。

这篇文章盘点一下 EF Core 的几种数据查询方式,内容较多分上下两篇。

点击上方或后方蓝字,阅读 EF Core 系列合集。

4070af2529d7610d2cc16b61360bbae7.png

简单查询

在 EF Core 中,每个查询都由三个主要部分组成:

  • 通过 ApplicationContext 的 DbSet 属性连接到数据库

  • 使用一系列的 LINQ 或 EF Core 命令

  • 执行查询

这是一个最简单的示例:

public void Run()
{var accounts = _context.Accounts.Where(s => s.Age > 16).ToList();
}

从这个查询中,我们可以看到查询的三个主要部分:

「_context.Accounts」 是查询第一部分,通过 DbSet<Account> 属性,访问数据库中的 Account 表。

「Where(s => s.Age > 25)」 是查询的第二部分,使用 LINQ 方法筛选需要的行。

最后,「ToList()」 方法用来来执行这个查询。

需要注意的是,当我们在 EF Core 中编写只读查询时,可以添加 AsNoTracking 方法提高查询效率:

_context.Accounts.AsNoTracking()

使用 AsNoTracking 方法时,EF Core 不会跟踪加载实体的变化。

关系型查询

在 EF Core 查询导航属性(表关联字段)的方式有多种:「贪婪加载」「显式加载」「懒惰加载」

贪婪加载

贪婪加载也叫预先加载。

所谓贪婪加载,就是在查询结果中包含导航关系,而这就需要明确的要求。

比如这个示例中,Account 拥有两个导航属性:

5de9908a753bc211ecd6837c8187a5f7.png

AccountDetails属性是一对一的导航关系;

AccountSubjects属性是一对多的导航关系。

运行这个简单查询的结果如下:

23cf1aa140c3fa6848dad70a3e03999d.png

可以发现,控制台的结果中,两个导航属性的值都是 Null

在 EF Core 中,只有明确要求的情况下,才会在结果中包含导航关系。这个简单查询中,没有明确要求包含导航关系。

如果使用贪婪加载,可以让 EF Core 在查询结果中包含导航属性的值。

贪婪加载通过使用 Include() 和 ThenInclude() 方法实现,如下所示:

var accounts = _context.Accounts.Include(e => e.AccountSubjects).Where(s => s.Age > 16).ToList();

Include 方法用来加载第一层导航关系,如果想进一步加载导航关系呢?

比如 AccountSubjects 属性中有两个一对一导航,分别是 Accout 属性和 Subject 属性:

a56dabb1a234db19b548888405441f4c.png

如果我们想通过 AccountSubjects 导航属性,进一步查询出 Subject 属性,就可以这么做 :

var accounts = _context.Accounts.Include(e => e.AccountSubjects).ThenInclude(s => s.Subject).Where(s => s.Age > 16).ToList();

ThenInclude 方法用来进一步加载导航关系。该方法可以无限递进非关系深度,如果关系不存在,查询也不会失败,只是不会返回任何东西。

「贪婪加载的优点是,以一种高效的方式,查询了关系型数据,使用了最少的数据库访问次数;」

「它的缺点是,一次性加载了所有的数据,即使我们不需要其中的某些数据。」

显式加载

所谓显式加载,就是 EF Core 显式地将关系,加载到已经加载的实体中。

比如这个示例:

var account = _context.Accounts.FirstOrDefault();_context.Entry(account).Collection(ss => ss.AccountSubjects).Load();foreach (var accountSubject in account.AccountSubjects)
{_context.Entry(accountSubject).Reference(s => s.Subject).Load();
}

我们首先加载的是 Acount 实体,然后通过 AccountSubjects 导航属性关联所有相关的子项。

在这种情况下,Acount 实体被称为主实体。

Collection 方法可以把一个集合纳入主实体,Reference 方法可以把单一的实体纳入主实体。

Account 实体通过使用 Collection 方法,包含了 AccountSubjec 集合。

AccountSubject 实体通过使用 Reference 方法,包含了 Subject 实体。

使用显式加载时,除了 Load 加载方法,还可以使用查询方法,它允许将查询应用到关系中:

var count = _context.Entry(account).Collection(a => a.AccountSubjects).Query().Count();var subjects = _context.Entry(account).Collection(a => a.AccountSubjects).Query().Select(s => s.Subject).ToList();

「显式加载的好处是,只有当真正需要的时候,我们才会在实体类上加载一个导航关系。」

另一个好处是,如果我们有复杂的业务逻辑,那就可以分别加载导航关系。

另外,导航关系加载可以封装到一个方法、甚至是一个类中,从而使代码更容易阅读和维护。

不过,这种方法的缺点是,会产生更多的数据库查询次数,来加载所有需要的关系,会降低查询的效率。

懒惰加载

懒加载也叫延迟加载、按需加载,它和贪婪加载相反,顾名思义,暂时不需要的数据就不加载,而是推迟到使用它时再加载。

延迟加载是一个比较重要的数据访问特性,它可以有效地减少与数据源的交互。

注意,这里所指的交互不是指交互次数,而是指交互的数据量。

EF Core 中默认是不开启这个功能的,因为在使用不当的情况下,它会降低应用的性能。

想要使用懒加载,最简单的办法就是安装 Microsoft.EntityFrameworkCore.Proxies 库,使用代理模式实现懒加载。

在上下文类的配置方法中启用懒加载代理:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{optionsBuilder.UseLazyLoadingProxies();
}

配置完成后,EF Core 会为任何可以被重载的导航属性,启用懒惰加载。

需要注意的是,这是一种全局配置,所有的导航属性都必须使用 virtual 修饰,否则会发生异常错误。

不过,这样一来的话,所有的导航属性都默认启用了懒加载。

除了使用代理模式,还可以使用 EF Core 中的懒加载服务,这种方式不需要用 virtual 修饰导航属性,而且可以只针对特定实体进行懒加载。

具体来看示例:

public class Account
{private readonly ILazyLoader _lazyLoader;public Account(ILazyLoader lazyLoader){_lazyLoader = lazyLoader;}private ICollection<AccountSubject> _accountSubjects;public ICollection<AccountSubject> AccountSubjects{get => _lazyLoader?.Load(this, ref _accountSubjects);set => _accountSubjects = value;}}

使用构造函数注入的方式,将 ILazyLoader 服务注入到实体类中,然后修改需要开启懒加载的字段。

需要注意的是,滥用懒加载,会造成性能上的问题。

虽然懒加载只在需要读取关联数据的时候才进行加载,但是如果在遍历中使用的话,每次读取一条数据,那么就会查询一次数据库,增加了访问数据库的次数,会导致数据库的压力增大。

贪婪加载也一样会有性能上的问题,因为一次性读取所有相关的数据,有可能会导致部分数据在实际上用不到,从而使查询数据的效率降低。

所以,我们应该清楚什么时候应该使用哪种加载方式:

如果在开发时不确定是否会需要相关联的数据,那么可以选择懒加载,待确定需要后再加载它。

如果在开发时就可以预见,需要一次性加载所有的数据,而且需要包含导航关系的所有数据, 那么使用贪婪加载是比较好的选择。

更多精彩内容,请关注我▼▼

20ea739fb2bbe4a1dafd07808f4c2832.gif

如果喜欢我的文章,那么

在看和转发是对我最大的支持!

(戳下面蓝字阅读)

38f1ce930e2c942c67f5a5b709720046.png

推荐关注微信公众号:码侠江湖

                        886714d5bef690057cb2ed68897e7635.png觉得不错,点个在看再走哟

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

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

相关文章

《零基础看得懂的C++入门教程 》——(3)表达式花样挺多鸭

一、学习目标 了解变量之间的计算了解什么是表达式了解什么是自增、自减 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学习方法和一些…

prometheus python client

为什么80%的码农都做不了架构师&#xff1f;>>> 当我刚开始准备使用Python写一个promethues的client的时候&#xff0c;并没有想到过程这么麻烦。github上的大佬们也没兴趣帮我解决这些细节的问题。以下是我在使用prometheus_client遇到的一些问题&#xff0c;仅供…

【遥感数字图像处理】实验:遥感影像分类(监督、非监督分类)完整流程(Erdas版)

一.实验目的: 理解计算机图像分类的基本原理,掌握数字图像非监督分类以及监督分类的具体方法和过程,以及两种分类方法的区别。 二.实验平台:ERDAS IMAGINE 9.1 三.实验要求:掌握非监督分类;非监督分类结果评价;监督分类;监督分类结果评价;分类后处理。 四.实验…

重大跨越!Windows 11 23H2 25115 推送:2023 年更新测试开启,水印回归

面向 Dev 频道的 Windows 预览体验成员&#xff0c;微软现已发布 Windows 11 预览版 Build 25115。主要变化1.微软宣布从 Dev 频道切换到 Beta 频道的选项正式关闭&#xff0c;Beta 频道将继续测试 Windows 11 版本 22H2&#xff0c;而 Dev 频道将开启 2023 年更新 Windows 11 …

《零基础看得懂的C++入门教程 》——(4)条件判断原来如此

一、学习目标 了解什么是条件判断了解多个条件判断了解输入了解什么是逻辑与、逻辑或 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学…

Django学习笔记(4)

为什么80%的码农都做不了架构师&#xff1f;>>> 首先提一个问题&#xff1a;在Django中如何处理CRSF(Cross-site request forgery)? 先看一下CSRF原理。 其实就是恶意网站利用正常网站的cookie去非法请求。 ##Java处理方式## 一般做法需要后台和前端配合采取策略去…

.NET版OCR紧随PP-OCRv3重磅发布

.net版OCR地址PaddleOCRSharp&#xff1a;https://gitee.com/raoyutian/paddle-ocrsharpPaddleOCRSharp是一个基于PaddleOCR的C代码修改并封装的.NET的工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同时针对小图识别不准的情况下&a…

《零基础看得懂的C++入门教程 》——(5) 容我套个娃 循环

一、学习目标 了解循环的使用方法 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学习方法和一些原理C与C都是相同的《脱离学习误区》 …

Android两个注意事项.深入了解Intent和IntentFilter(两)

深入理解Intent和IntentFiler(二)转载请表明出处&#xff1a;http://blog.csdn.net/u012637501(嵌入式_小J的天空) 在上一篇文章中&#xff0c;我们比較具体学习了"Intent"的相关知识&#xff0c;如今将学习怎样设置Intent对象的这些属性以及怎样使用他们来启动组件。…

Oracle常用sql语句(一)

Sql的分类DDL操作数据库表列等表基本的操作主键索引视图 常用数据类型字符串类型数字类型日期类型LOB类型LONG类型 数据转换character datenumbercharacter通用函数条件表达式Sql的分类 DDL &#xff08;Data Definition Language&#xff09;&#xff1a;数据定义语言&#xf…

ASP.NET Web API 实现客户端Basic(基本)认证 之简单实现

优点是逻辑简单明了、设置简单。 缺点显而易见&#xff0c;即使是BASE64后也是可见的明文&#xff0c;很容易被破解、非法利用&#xff0c;使用HTTPS是一个解决方案。 还有就是HTTP是无状态的&#xff0c;同一客户端每次都需要验证。 实现&#xff1a; 客户端在用户输入用户名及…

WPF|分享一个登录界面设计

分享一个登录界面&#xff0c;先看效果图&#xff1a;准备文中使用到了一些图标&#xff1a;我们可以从 iconfont[1]免费下载&#xff1a;代码简单说明请随手创建一个WPF项目&#xff08;.NET Framework、.NET 5\6\7皆可&#xff09;&#xff0c;使用tree /f命令看看最终的文件…

《零基础看得懂的C++入门教程 》——(6)自己动手写个函数

一、学习目标 了解C语言的自定义函数的使用方法了解C语言自定义函数的传参了解C语言自定义函数的返回值 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点…

【计算机图形学】实验:C#语言采用GDI+定义笔刷并填充图形完整实验操作流程

一、实验目的: 熟练掌握在.net环境下对笔刷的定义,并可用定义好的笔刷填充多边形。 二、实验准备: 学习在.net环境下GDI+所提供的5种笔刷类型,掌握定义笔刷的方法和填充图形的函数,如FillRectange ( )、FillEllipse ( )等。 三、实验内容: 在.net环境中设计一个窗体…

管道模式 pipe

先放一个图&#xff0c;预则立嘛 PipelinePattern.rar 这里是 不完整的码转载于:https://www.cnblogs.com/ganmk--jy/p/5525897.html

《零基础看得懂的C++入门教程 》——(7)小数组玩起来

一、学习目标 了解数组的使用方法了解一维数组的使用方法了解一维数组与循环的使用方法 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c…

SSO 方案演进

1背景介绍 随着业务与技术的发展&#xff0c;现今比以往任何时候都更需要单点登录 SSO 身份验证。现在几乎每个网站都需要某种形式的身份验证才能访问其功能和内容。随着网站和服务数量的增加&#xff0c;集中登录系统已成为一种必要。在本文中&#xff0c;我们将讨论下 …

《零基础看得懂的C++入门教程 》——(8)搞定二维数组与循环嵌套

一、学习目标 了解二维数组的使用方法了解循环嵌套的使用方法 目录 预备第一篇&#xff0c;使用软件介绍在这一篇&#xff0c;C与C使用的软件是一样的&#xff0c;查看这篇即可&#xff1a;《软件介绍》 想了解编译原理和学习方法点这篇&#xff0c;学习方法和一些原理C与C都…

常见的Ubuntu命令30条(一)

Ubuntu命令是指在Ubuntu操作系统中用于执行各种任务和操作的命令行指令。这些命令可以用于管理系统、配置网络、安装软件、浏览文件等。Ubuntu命令通常在终端&#xff08;Terminal&#xff09;应用程序中输入并执行。 在Ubuntu中&#xff0c;有许多常用的命令和指令。以下是一…

【计算机图形学】实验:C#.net环境下的图形变换完整实验操作流程

一、实验目的: 熟练掌握在.net环境下对图形的变换方法。 二、实验准备: 学习图形变换的基本算法,如平移、旋转、缩放等,以及在.net环境下变换图形的基本方法。 三、实验内容: 在.net环境中利用变换图形的基本方法对图形进行变换,包括平移、旋转、缩放、对称、复合变…