.net EF Core专题:EF Core 读取数据时发生了什么?_实用技巧

来源:脚本之家  责任编辑:小易  

NET Core 使用Dapper 操作MySQL 数据库,.NET Core 使用Dapper。目前官方没有出.NET Core MySQL 驱动,但是已经有第三方进行改动封装出.NET Core MySQL Connector 预览版。Dapper 也已经出了.NET Core 预览版。Dapper dot net 是一个轻量型的ORM,但是性能很强大。有了.NET Core MySQL Connector 我们可以直接使用ADO.NET 操作数据库。目前EF Core 暂时不支持MySQL,本篇主要讲解使用Dapper 操作 MySQL。第三方 MySQL Connector:https://github.com/SapientGuardian/mysql-connector-net-netstandardDapper:https://github.com/StackExchange/dapper-dot-net新建项目新建一个.NET Core控制台应用程序 NETCoreMySQLwww.zgxue.com防采集请勿采集本网。

原文:https://bit.ly/2UMiDLb

在asp.net core 里非常建议使用entity framework,因为新的entity framework core定义了一套接口标准,就如同ado.net一样,只要有厂家实现了这套接口就行,而且厂

作者:Jon P Smith

net core何时支持datatable 我来答 English4i 2017-02-13 English4i 采纳数:238 获赞数:45 LV8 擅长:暂未定制 向TA提问私信TA 展开全部 DataSet 是离线的数据源 DataTab

翻译:王亮

1。 选择其中的两个表作为示例. 在工程中添加ADO先简单说一下如何创建环境.NET Entity Data Model.. 在Visual Studio中创建一个示例工程,请直接跳过。如果

声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的。其中可能会去除一些本人实在不知道如何组织但又不影响理解的句子。

这里我们选择 ASP.NET Core Web Application (.NET Core) 这里选择web 应用程序,然后更改身份验证 改为 不进行身份验证 然后再包管理控制台里执行下面两条

本文将为你详细描绘 EF Core 从数据库中读取数据的“幕后”视图。我将揭开两种数据库读取方式的面纱:一个是普通的查询,另一个是使用 AsNoTracking 方法的非跟踪查询。我还将通过一个实验来演示我是如何解决我的一个客户遇到的性能问题。

EnsureCreated 是如果当前数据库不存在按照当前 model 创建,如果存在则不管了。 Migrate 是如果当前数据库不存在按照当前 model 创建,如果存在则将数据库调整

我假设你对 EF Core 已经有了一定的认识,但在深入学习之前,我们先来了解一下如何使用 EF Core,以确保我们已经掌握了一些基本知识。这是一个“深入研究”的课题,所以我准备大量的技术细节,希望我的描述方式你能理解。

本文是“深入理解 EF Core”系列中的第一篇。以下是本系列文章列表: 当 EF Core 从数据库读取数据时发生了什么?(本文) 当 EF Core 写入数据到数据库时发生了什么?(敬请期待)

概要

EF Core 有两种方法从数据库中读取数据(也称为查询):普通 LINQ 查询和包含 AsNoTracking 方法的非跟踪 LINQ 查询。 这两种方法查询的返回类(被称为实体类),它连接的其它的实体类(即所谓的导航属性)也被同时加载,但这两种法如何连接及连接的内容是不一样的。 普通查询接受的是 DbContext 执行读取时所有数据的副本——此时的实体类称为被跟踪。这允许加载的实体类参与数据库的更新操作。 普通查询还会有一些其它的复杂底层实现,称为关系修补(fixup),用于描述读入的实体类和其他被跟踪实体之间的连接关系。 AsNoTracked 非跟踪查询没有副本,所以它没有被跟踪——这意味着它比普通查询更快。这也意味着它不会用于数据库的写操作。 最后,我将展示 EF Core 普通查询中一个鲜为人知的特性,以此作为示例,说明通过导航属性连接实体类的关系是多么智能。

EF Core 如何读取数据库数据

提示:如果你已经对 EF Core 有一定的认识,那么你可以跳过这一节,这部分只是一个如何读取数据库的例子。

为了能让你更好地理解,我先描述一个数据库结构,然后再给出一个简单的数据库读取示例。下面是一些基本表的结构和它们之间的关系。

这些表被映射到具有类似名称的类,例如 Book、BookAuthor、Author,这些类的属性名称与表的字段名称相同。由于篇幅有限,我不打算展开来讲这些类,但您可以在我的 GitHub 仓库[1]中查看这些类。

EF Core 读取数据库需要下面五部分:

    数据库服务器,如 SQL server, Sqlite, PostgreSQL 等。 具有数据的数据库。 映射到数据表的类(称为实体类)。 一个继承 DbContext 的类,该类包含 EF Core 的配置。 最后,从数据库读取数据的命令。

下面的单元测试代码来自我的 GitHub 创库[2],展示了一个简单的示例,它从现有数据库中读取 4 个 Book 实体及其关联的 BookAuthor 和 Authors 实体。

仓库地址:https://bit.ly/2Yza7QQ

[Fact]public void TestBookCountAuthorsOk(){ //SETUP var options = SqliteInMemory.CreateOptions<EfCoreContext>(); //code to set up the database with four books, two with the same Author using (var context = new EfCoreContext(options)) { //ATTEMPT var books = context.Books .Include(r => r.AuthorsLink) .ThenInclude(r => r.Author) .ToList(); //VERIFY books.Count.ShouldEqual(4); books.SelectMany(x => x.AuthorsLink.Select(y => y.Author)) .Distinct().Count().ShouldEqual(3); }}

现在,如果我们将单元测试代码对应到上面的 5 部分,结果是这样的:

    数据库服务器——第 5 行:我选择了一个 Sqlite 数据库服务器,在本例中是 SqliteInMemory.CreateOptions 方法,它使用我的一个 NuGet 包 EfCore.TestSupport 创建了一个内存数据库(内存中的数据库对于单元测试非常有用,因为你可以为这个测试建立一个新的空数据库)。 具有数据的数据库——第 6 行:我将在下一篇文章介绍数据是如何写入数据库的,现在假设有一个数据库包含 4 本书信息,其中两本书的作者是同一个人。 实体类——代码里这里没有展示,但是你可以在这里查看这些类[1]。其中有一个 Books 实体类,通过一个名为 BookAuhor 的实体类多对多关联 Authors 实体类。 一个继承 DbContext 的类——第 7 行:EfCoreContext 类继承了 DbContext 类并配置了从类到数据库的映射关系(你可以在我的 GitHub 仓库[3] 中查看该类)。 从数据库读取数据的命令——第 10 到 13 行,这是一个查询:
第 10 行 — context 为 EfCoreContext 的实例,通过它访问你的数据库,.Books 表示您希望访问 Books 表。 第 11 行 — Include 被称为贪婪加载,它告诉 EF Core 当它加载 Books 时,也应该加载关联到的所有 BookAuthor 实体类。 第 12 行 — ThenInclude 是继续贪婪加载,它告诉 EF Core 当它加载一个 BookAuthor 时,它也应该加载关联到该 BookAuthor 的 Author 实体类。

所有这一切查询出来是一个结果集,其中有普通属性,像 Books 的 Title 属性;有关联实体类的导航属性,像 Books 的 AuthorsLink 属性。

这个示例称为查询或读取,也是四种数据库访问类型之一,即 CRUD(新增、读取、更新和删除)。我将在下一篇文章中介绍新增和更新。

EF Core 如何表示读取的数据

当你查询数据库时,EF Core 会将数据库返回的数据转换为实体类并填充导航属性的值。在本节中,我们将研究两种类型的查询步骤——普通查询(即没有 AsNoTracking 方法,也称为读写查询)和添加了 AsNoTracking 方法的非跟踪查询(称为只读查询)。

我们先来看一下最初 LINQ 语句是如何转换成数据库相应的查询命令然后返回数据的。对于我们将要看到的两种类型的查询来说,这是很常见的操作。关于查询的第一部分,请参见下图。

有一些非常复杂的代码将你的 LINQ 转换为数据库查询命令,但这些内部细节我们不必关心。如果你的 LINQ 不能被翻译,你会从 EF Core 得到一个异常消息,其中包含类似“不能被翻译”的描述词语。此外,当数据返回时,像 Value Converters[4] 这样的特性可能会调整数据。

本节展示了查询的第一部分,其中 LINQ 被转换为数据库命令并返回所有正确的值。现在我们来看查询的第二部分,在这里 EF Core 获取返回值并将它们转换为实体类的实例,并填充导航属性。我们将分别看看两种类型的查询。

1. 普通查询(读写查询)

普通查询读取数据的方式可以修改数据并更新到数据库,这就是我将其称为读写查询的原因。它不会自动更新数据(请参阅下一篇文章,了解如何写入数据库)。如果你要更新数据,你的查询必须是读写查询。

我在介绍中给出的示例执行的是一个普通读写查询,读取带有 AuthorsLink 实例的示例。下面是该示例的查询部分的代码:

var books = context.Books .Include(r => r.AuthorsLink) .ThenInclude(r => r.Author) .ToList();

然后 EF Core 通过三个步骤将这些值转换并填充含有导航属性的实体类。下图显示了这三个步骤以及生成的实体类及其导航属性的实体类。

让我们来分析一下这三个步骤:

    创建类并填充数据。它接受数据库返回的值,并填充非导航(称为标量)属性、字段等。在 Book 实体类中,是 BookId(主键)、Title 等属性——参见上图左下角浅蓝色矩形。 修补关联关系。首先是填入主键和外键的信息,它们定义如何相互关联数据。然后,EF Core 使用这些键设置实体类之间的导航属性(如图中蓝色粗线所示)。这个关系的修补所需的信息不仅是查询读入的实体类,它还会查看 DbContext 中跟踪的每个实体,并填充导航属性。这是一个强大的功能,但你的被跟踪实体越多,所需消耗时间也越多——这就是为什么需要 AsNoTracking 来实现更快的查询。 创建跟踪快照。跟踪快照是返回给用户的实体类的一个副本,加上它所隐藏的与每个实体类的关联关系——若一个实体处于被跟踪状态,这意味着它将会发生修改并会写入到数据库中。

2. 非跟踪查询(只读查询)

非跟踪查询,即使用 AsNoTracking 方法的查询,是一个只读查询。这意味着,当 SaveChanges 方法被调用时,你读取的任何内容都不会被写入数据库。非跟踪查询的查询效率更高,在下一节中,我将介绍非跟踪查询以及与普通查询的其他区别。

在前文的示例之后,我修改了查询代码,添加了下面的 AsNoTracking 方法(请看第 2 行):

var books = context.Books .AsNoTracking() .Include(r => r.AuthorsLink) .ThenInclude(r => r.Author) .ToList();

这里的 LINQ 查询只有上面的普通查询的前两个步骤(没有第三个步骤)。下图显示了 AsNoTracking 查询的步骤。

步骤如下:

    创建类并填充数据。它接受数据库返回的值,并填充非导航(称为标量)属性、字段等。在 Book 实体类中,是 BookId(主键)、Title 等属性——参见上图左下角浅蓝色矩形。 修补关联关系。首先是填入主键和外键的信息,它们定义如何相互关联数据。然后,EF Core 使用这些键设置实体类之间的导航属性(如图中蓝色粗线所示)。这个关系的修补所需的信息不仅是查询读入的实体类,它还会查看 DbContext 中跟踪的每个实体,并填充导航属性。这是一个强大的功能,但你的被跟踪实体越多,所需消耗时间也越多——这就是为什么需要 AsNoTracking 来实现更快的查询。

普通查询和非跟踪查询的区别

现在让我们比较这两种查询比较明显的区别。

    非跟踪查询查询的性能更好。使用非跟踪查询查询的主要原因是性能。非跟踪查询查询表现为:
稍微快一点,使用的内存稍微少一点,因为它不需要创建跟踪快照。 避免没有必要的跟踪快照可以提高 SaveChanges 的性能,因为它不必检查跟踪快照以查找更改。 稍微快一点,因为修补关联关系时没有所谓的身份解析。这就是为什么你会得到两个具有相同数据的 Author 实例。

    非跟踪查询修补关联关系时只链接查询中的实体。在普通查询中,我已经说过修补关联关系时连接的是查询中的实体和当前跟踪的实体,但是非跟踪查询只修补查询中的实体关系。 非跟踪查询并不总是代表数据库关系。这两种类型查询之间的关系修补的另一个区别是,非跟踪查询关系修补更快,它不需要标识的解析。这可以为数据库中的同一行生成多个实例——见上图右下角蓝色的 Author 实体和注释。如果只是向用户显示数据,那么这种差异并不重要,但是如果具有业务逻辑,那么多个实例不能正确反映数据的结构,就可能会有问题。

对层级数据有用的关系修补特性

关联关系修补的步骤是非常智能的,特别是在普通查询中。下面我想向你展示我是如何利用关系修补的特性来解决一个客户项目中的性能问题的。

我曾在一家公司工作,那里的许多数据处理都是层次化结构的,即数据具有一系列深度不确定的关联关系。问题是我必须先解析整个层次结构,然后才能呈现这些数据。我最初是通过贪婪的方式加载前两个层级,然后显式地加载更深的层级来实现这一点的。它可以工作,但是性能非常慢,并且数据库因大量单数据库访问而超载。

这不得不让我思考解决办法,如果普通查询的关系修补那么智能的话,它能帮助我提高查询的性能吗?它可以!让我给你举一个公司员工的例子。下图显示了我们想要加载的公司的层次结构。

你可以接龙式地使用 .Include(x => x.WorksForMe).ThenInclude(x => x.WorksForMe)… 等等来加载所需的层级信息,但结果是一个 .Include(x => x.WorksForMe) 就够了。因为 EF Core 的关系修补为你做了剩下的事情,这一点很惊奇,但也很有用。

例如,如果我想查询角色为 Development 的所有员工(每个员工都有一个名为 WhatTheyDo 的属性和名为 Role 的属性,该 Role 包含他们工作的部门),我可以这样编写代码:

var devDept = context.Employees .Include(x => x.WorksFromMe) .Where(x => x.WhatTheyDo.HasFlag(Roles.Development)) .ToList();

 这将创建一个查询,用于加载角色为 Development 的所有员工,并且在员工实体类上修补与 WorksFoMe 导航属性(集合)和 Manager 导航属性(单个)的关系。通过只执行一个查询,既提高了查询花费的时间,又减少了数据库服务器上的负载。

总结

你已经看到了两种类型的查询,我称之为 a)普通的读写查询,和 b) 非跟踪的只读查询。对于每一种查询类型,我都向你展示了 EF Core “幕后”是如何读取数据并展示的。他们工作方式的不同也表现出他们的优势和劣势。

非跟踪查询是只读查询的解决方案,因为它比普通读写查询更快。但是您应该记住关系修补的机制,它可以在数据库只有一个关系的情况下创建类的多个实例。

普通的读写查询是查询跟踪实体的解决方案,这意味着你可以在创建、更新和删除数据时使用它们。普通的读写查询确实会占用更多的时间和内存资源,但是有一些有用的特性,比如自动链接到其他被跟踪的实体类实例。

我希望这篇文章对您有用。祝你编程快乐!

[1]. https://bit.ly/2MXK3ZY

[2]. https://bit.ly/2Yza7QQ

[3]. https://bit.ly/2Y0UORO

[4]. https://bit.ly/2YEyg8j

查了一下,可以用命令行生成相应的文件:Scaffold-DbContext"Server=.\\SQLExpress;Database=SchoolDB;Trusted_Connection=True;Microsoft.EntityFrameworkCore.SqlServer-OutputDir Models连接字符串放json里面ConnectionStrings":{MbkDbConstr":"Data Source=(localdb)\\\\MBK;Database=MbkTest;}参考资料:网页链接内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • 从efcore上下文的使用到深入剖析di的生命周期最后实现自动属性注入
  • asp.net实现存储和读取数据库图片
  • asp.net上传excel文件并读取数据的实现方法
  • asp.net连接数据库读取数据示例分享
  • asp.net treeview读取数据库实例
  • dropdownlist绑定数据表实现两级联动示例
  • asp.net 文章内容分页显示的代码
  • asp.net调用系统设置字体文本框的方法
  • 批量账号的login测试功能实现
  • asp.net core静态文件使用教程(9)
  • asp.net mvc验证码类使用
  • .net中openfiledialog使用线程报错的解决方法
  • c# 递归函数详细介绍及使用方法
  • asp.net数据输出到excel表格中
  • vs2010无法打开项目文件的原因分析及解决方法
  • 请问asp.net core mvc怎么使用ef连接现有数据库? 百度知道
  • net core 怎么操作数据库 百度知道
  • net core 怎么操作数据库 百度知道
  • net core 怎么操作数据库
  • asp.net core里面,EF和NH哪个对Oracle的支持更好? 百度知道
  • net core何时支持datatable 百度知道
  • EntityFramework Core 1.1是如何创建DbContext实例的呢 百度知道
  • ef core使用code first无法为mysql数据表设置字段默认值,该怎么办 ...
  • 在.net Core中Migrate 和EnsureCreated分别用于什么情形 百度知道
  • asp.net core Mvc 怎么连接sql server 百度知道
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全基础应用实用技巧自学过程首页asp.net实用技巧从efcore上下文的使用到深入剖析di的生命周期最后实现自动属性注入asp.net实现存储和读取数据库图片asp.net上传excel文件并读取数据的实现方法asp.net连接数据库读取数据示例分享asp.net treeview读取数据库实例dropdownlist绑定数据表实现两级联动示例asp.net 文章内容分页显示的代码asp.net调用系统设置字体文本框的方法批量账号的login测试功能实现asp.net core静态文件使用教程(9)asp.net mvc验证码类使用.net中openfiledialog使用线程报错的解决方法c# 递归函数详细介绍及使用方法asp.net数据输出到excel表格中vs2010无法打开项目文件的原因分析及解决方法java正则表达式 pattern和matche未将对象引用设置到对象的实例 (asp.net(c#)网页跳转七种方法小结未能加载文件或程序集“xxx”或它asp.net“服务器应用程序不可用”asp.net中的几种弹出框提示基本实asp.net gridview 72般绝技asp.net生成excel并导出下载五种asp.net对路径"xxxxx"asp.net汉字转拼音和获取汉字首字asp.net中使用自定义控件的方式实现一个分mvc异步分页代码分享asp.net页面优化 性能提升8倍的方法asp.net core mvc 中实现中英文切换的示例visual studio 2017 针对移动开发的新特性asp.net多选项卡页面的创建及使用方法概述.net开发过程中bin目录下面几种文件格asp.net页面某些选项进行提示判断具体实现datagridview右键菜单自定义显示及隐藏列使用vscode开发和调试.net core程序的方法
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved