[翻译 EF Core in Action 1.9] 掀开EF Core的引擎盖看看EF Core内部是如何工做的

Entity Framework Core in Action

Entityframework Core in action是 Jon P smith 所著的关于Entityframework Core 书籍。原版地址. 是除了官方文档外另外一个学习EF Core的不错途径, 书中由浅入深的讲解的EF Core的相关知识。由于没有中文版,因此本人对其进行翻译。 预计每两天一篇更新 PS: 翻译不免限于本人水平有不许确的地方,建议英文水平不错的同窗直接查看原版,有不足的地方欢迎指正html

第一部分目录导航

掀开EF Core的引擎盖看看EF Core内部是如何工做的

建立了MyFirstEfCoreApp应用程序后,你如今能够经过它查看EF Core的工做原理,重点不在于应用程序的代码,而是在读取和写入数据到数据库时EF Core内部会发生什么. 个人目标是让你了解EF Core的工做机制,当你深刻研究本书其他部分的命令时,这会颇有帮助git

注 书中仅给出了关键代码, 完整示例在 https://github.com/JonPSmith/EfCoreInAction/tree/Chapter01

数据库建模

在对数据库进行操做以前,EF Core必须进行数据库建模. 数据库建模是EF Core经过实体类和其余EF Core配置来描述数据库的方法. EF Core在全部的数据库访问中使用创建的模型github

建模在建立应用程序的DbContext时就开始了,在本例中是AppDbContext(如图1.5所示,在上一篇文章中). 它有属性DbSet ,使得经过代码能够访问数据库 数据库

图1.6描述了建模过程的概述,它会帮助你理解EF Core数据库建模的过程. 后续的章节将介绍一系列配置数据库的相关命令,在本文中使用默认配置缓存

图1.6展现了EF Core在AppDbContext的建模步骤,下文对此过程进行更详细的说明学习

  1. EF Core查看DbContext并找到全部公共的DbSet 属性,并使用属性名为表定义初始名称.
  2. EF Core查看DbSet 的泛型类,查看类的属性构建列名,类型等. 它还会查找类和属性用于提供额外建模配置的特殊Attribute
  3. EF Core查找DbSet 类中引用的其余类. 在咱们的例子中Book类有一个对Author类的引用,因此EF Core也会查看它. 它对Author类执行与步骤2相同的操做. 同时它使用类名Author作为表名
  4. 建模过程的最后一个步骤, EF Core运行DbContext的虚方法OnModelCreating, 能够经过重写OnModelCreating方法使用fluent Api进行更多的建模配置,但本例中为了保持示例的简单并无这样作
  5. EF Core根据收集的信息建立数据库的内部模型,并缓存数据库模式,以便提高访问速度. 在以后的全部的数据库访问中使用此模型

你可能会注意到图1.6并无展现数据库,由于EF Core构建内部模型时,它不会去查看数据库. 我强调这一点是为了说明构建一个的数据库模型多么重要,若是EF Core认为数据库模型和实际的数据库不匹配,就会出现问题.net

在你的应用程序中你可使用EF Core来建立数据库,这会避免出现不匹配的状况. 若是你想要一个良好且高效的数据库,那么在你的代码中编写良好的数据库模型是很是重要的,这样建立的数据库会是高效的. 建立,更新和管理数据库结构是一个很大的主题,将在11章详细介绍翻译

从数据库中读取数据

如今能够访问数据库了. 咱们使用List(l)命令,让程序读取数据库并在终端上打印信息. 图1.7显示了输出3d

下面列出代码清单, 用于将全部的图书与做者输出到控制台code

EF Core使用Linq(语言集成查询)执行它想要执行的命令,使用.net类保存数据

代码清单中粗体显示的两行代码进行了数据库访问. 下面让咱们看看EF Core如何使用Linq代码访问数据库并返回数据. 图1.8跟随着这些代码走进EF Core内部,看看鲜为人知的故事...

从数据库中读取数据的过程以下

  1. Linq查询中的db.Books.AsNoTracking().Include(a => a.Author)访问应用程序DbContext的DbSet 属性, Include(a => a.Author)显式加载关系的Author部分. 数据库提供程序将Linq翻译成访问数据库的SQL命令. SQL被缓存以便若是再次使用相同的查询语句时避免从新翻译的成本
    EF Core在数据库访问方面会尽量高效. 在这种状况下,它将须要读取的两张表(Books和Author)组合到一个大表中,在一次数据库访问中完成工做. 下面的清单展现了EF Core和数据库提供程序建立的SQL
    SELECT [b].[BookId], [b].[AuthorId], [b].[Description], [b].[PublishedOn], [b].[Title], [a].[AuthorId], [a].[Name], [a].[WebUrl] FROM [Books] AS [b] INNER JOIN [Author] AS [a] ON [b].[AuthorId] = [a].[AuthorId]
  2. 数据库提供程序读取数据后,EF Core经过如下过程放置数据: (a) 建立.NET类的实例 (b) 使用数据库关系连接(外键),经过引用(称为关系修复)将.NET类连接在一块儿. 结果是一组以正确方式连接的.NET类实例. 在本例中两本书有相同的做者Martin Fowler,所以这两本书的做者属性指向同一个Author类
  3. 因为代码中包含 AsNoTraching, 因此EF Core知道禁止建立跟踪快照. 跟踪快照用于发现数据的变化, 你会在编辑WebUrl的示例中了解这一点. 因为这是一个只读查询,所以禁用跟踪快速会使查询更快

更新数据库

如今使用MyFirstEfCoreApp中的第二个命令update(u)来更新图书Quantum Networking做者的WebUrl列. 如图1.9所示,首先列出全部书籍,会看到最后一本书的做者没有WebUrl. 而后运行命令u,它将要求输入Url. 这时输入 httqs://entangled.moon(这是一个虚构的Url,httpqs-.-),在更新成功后再次列出全部的书籍,这时能够看到Web Url值已经更新

代码清单

图1.10展现了EF Core内部发生了什么并跟踪其进度,这比上一个read的示例复杂许多, 所以我会给你一些提示

图顶部的读取阶段与上一个读取示例相似,因此应该很熟悉. 在此基础上使用图书的标题作为过滤器载特定的图书. 重要的是第2点: 对数据进行跟踪

在图的下半部分你能够看到EF Core如何将加载的数据与跟踪快照进行比较并找到更改,能够看到只有WebUrl被更新了,它建立了一个SQL命令来只更新该列

图中已经描述了大部分步骤,下面介绍Author的WebUrl列如何更新的详细说明

  1. 应用程序使用LINQ查找包含做者信息的单个图书,EF Core将LINQ查询翻译为SQL命令,读取Title为Quantum Networking的行,返回Book和Author类的实例,由于使用了Single查询,因此还会检查是否只找到一行
  2. LINQ查询中没有AsNoTracking方法,因此该查询是一个具备跟踪的查询,EF Core建立了数据的跟踪快照
  3. 而后代码更改了Book的Author的WebUrl属性. 当调用SaveChanges时, 检测更改阶段会将跟踪的全部类与跟踪快照进行比较. 在这里它会检测到全部已更改的内容. 在本例中主鍵为3的Author实例的WebUrl属性值被更改
  4. 检测到更改后,EF Core将启动事务. 每一个数据库更新都以原子单位完成: 更改所有成功或者所有失败. 这很是重要,由于若是仅应用了部分更改,关系数据库可能会发生严重的错误
  5. 更新请求由数据库提供程序转换为SQL命令,若是执行成功则提交事务并返回SaveChanges方法,不然会抛出异常
相关文章
相关标签/搜索