深入理解 EF Core:EF Core 写入数据时发生了什么? (3)

下图显示了阶段 1 完成后的情况。用于设置一个新的 Book 实体类(左)和一个新的 BookAuthor 实体类(中),后者将 Book 连接接到一个现有的 Author 实体类(右)。

深入理解 EF Core:EF Core 写入数据时发生了什么?

阶段 1 这是调用任何 EF Core 方法之前的起点。

下一个图显示了执行 context.Add(book) 之后的情况。更改部分以粗体显示。

深入理解 EF Core:EF Core 写入数据时发生了什么?

你可能会惊讶于执行 Add 方法时所发生的事情。它将作为参数提供的实体的状态设置为 Added(在本例中为 Book 实体)。然后通过导航属性或外键值查看与该实体连接的所有实体。对于每个被连接的实体,它会执行以下操作(注意:我不知道它们执行的确切顺序)。

如果实体未被跟踪(即其当前状态为 Detached),则将其状态设置为 Added——在本例中,它是 BookAuthor 实体。

它用主键的值填充正确的外键的值。如果连接的主键还不可用,它将为跟踪的主键和外键数据的 CurrentValue 属性设置一个惟一的负数。你可以在上图中看到这一点。

它填充当前未设值的导航属性——如上图中所示。

最后一个阶段,即阶段 3,是调用 SaveChanges 方法时发生的情况,如图所示。

深入理解 EF Core:EF Core 写入数据时发生了什么?

在“写数据时数据库端发生了什么”一节中,数据库更改的任何列都被复制回实体类中,以便实体与数据库匹配。在本例中,数据更新到数据库时会把主键值更新到 Book 的 BookId 和 BookAuthor 的 BookId。
而且,此次数据库写入完成后,涉及的所有实体的状态都会被更新为 Unchanged。

对于上面这样一个很长的解释,很多时候你不需要知道这些细节,你只管它“工作了”就行。但是,当某些东西不能正常工作或者想做一些复杂的事情时,比如记录实体类的更改,那么了解这个就非常有用。

更新数据到数据库时发生了什么

上面的示例是关于向数据库添加新记录的,但是没有进行更新。在这一节中,我将展示当你更新数据库中已有的记录时会发生什么。这里使用我上一篇文章“EF Core 读取数据时发生了什么?”中讲到的查询例子。

这个更新很简单,只有三行,但是它在代码中有三个阶段:读取、更新和保存。

var books = context.Books.ToList(); books.First().PublishedOn = new DateTime(2020, 1, 1); context.SaveChanges();

下图展示了这三个阶段:

深入理解 EF Core:EF Core 写入数据时发生了什么?

如你所见,你使用的查询类型很重要——普通查询加载数据并把返回的实体保存一份“跟踪快照”,返回的实体类被称为“被跟踪的”。如果实体没有没跟踪,则无法更新它。

注意:上一节中的 Author 实体类也是被“跟踪”的。在这个例子中,Author 的跟踪状态告诉 EF Core Author 已经在数据库中,因此不会再次创建。

因此,如果你更改了加载的跟踪实体类中的任何属性,那么当你调用 SaveChanges 时,它会将所有跟踪的实体类与它们的跟踪快照进行比较。对于每个类,它遍历映射到数据库字段的所有属性。这个过程称为更改跟踪,它将检测被跟踪实体中的每一个更改,包括 Title、PubishedOn 等非关系属性。

在这个简单的示例中,只有 4 个 Book 实体,但在实际应用程序中,您可能已经加载了许多相互连接的实体类。在这一点上,比较阶段可能需要一段时间。因此,你应该尝试只加载需要更改的实体类。

注意:EF Core 有一个名为 Update 的命令,它用于更新每个属性/列的特定情况。EF Core 会自动跟踪更改,默认只更新已更改的属性/列。

每次更新都将创建一个 SQL UPDATE 命令,所有这些更新都将在一个 SQL 事务中执行。使用 SQL 事务意味着所有更新都作为一个整体,如果其中任何一部分失败,那么事务中的任何数据库更改都会失效。

从数据库删除数据时发生了什么

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxfsf.html