【EF Core】迁移与反向工程


简介

EF Core 提供两种方法来保持 EF Core 模型和数据库架构同步。至于我们应该选用哪个方法,请确定你是希望以 EF Core 模型为准还是以数据库为准。

迁移

如果希望以 EF Core 模型为准,请使用迁移。
在实际项目中,数据模型随着功能的实现而变化:添加和删除新的实体或属性,并且需要相应地更改数据库架构,使其与应用程序保持同步。 EF Core 中的迁移功能能够以递增方式更新数据库架构,使其与应用程序的数据模型保持同步,同时保留数据库中的现有数据。
当数据模型更改时,开发人员使用 EF Core 工具添加相应的迁移。EF Core 将当前模型与旧模型的快照进行比较,以确定差异,并生成迁移源文件。
生成新的迁移后,可通过多种方式将其应用于数据库。 EF Core 在一个历史记录表中记录所有应用的迁移,使其知道哪些迁移已应用,哪些迁移尚未应用。

反向工程

如果希望以数据库架构为准,请使用反向工程。
可通过将数据库架构反向工程到 EF Core 模型来生成相应的 DbContext 和实体类型。

创建和应用迁移的两种方式

dotnet cli工具

可用于windows、linux、macOS。这些命令以dotnet ef开头
安装dotnet core cli工具:

dotnet tool install --global dotnet-ef

包管理控制台工具

只能在VisualStudio中运行,以动词开头,例如:Add-MigrationUpdate-Database
需要安装Nuget包:

Install-Package Microsoft.EntityFrameworkCore.Tools

Microsoft.EntityFrameworkCore.Tools 包中包含 Microsoft.EntityFrameworkCore.Design
如果迁移文件在单独的项目中,迁移项目和主项目中都要安装包Microsoft.EntityFrameworkCore.Tools,主项目中也可以安装包Microsoft.EntityFrameworkCore.Design

Migrations目录

创建迁移后,会生成Migrations目录,里面包含以下文件:

  • XXXXXXXXXXXXXX_AddCreatedTimestamp-主迁移文件。 包含应用迁移所需的操作(在 Up 中)和还原迁移所需的操作(在 Down 中)。
  • MyContextModelSnapshot.cs--当前模型的快照。 用于确定添加下一迁移时的更改内容。
    文件名中的时间戳有助于保证文件按时间顺序排列,以便你查看更改情况。

迁移流程

安装Nuget包

Install-Package Microsoft.EntityFrameworkCore.Tools

创建迁移文件

cli:dotnet ef migrations add InitialCreate
vs:Add-Migration InitialCreate

InitialCreate是迁移的描述名称
EF Core将在项目中创建名为“Migrations”的目录并生成一些文件

应用迁移

添加迁移后,需要对其进行部署并将其应用于数据库。 有多种策略可用于执行此操作,生产环境和开发环境使用不同的策略。

cli:dotnet ef database update
vs:Update-Database

这种应用迁移的方法非常适合本地开发,但不太适用于生产环境。生产环境使用sql部署

其他迁移操作

删除迁移

有时,你可能在添加迁移后意识到需要在应用迁移前对 EF Core 模型作出其他更改。 要删除上个迁移,删除迁移后可对模型作出其他更改,然后再次添加迁移。请使用如下命令:

cli:dotnet ef migrations remove
vs:Remove-Migration

避免删除已应用到生产数据库的任何迁移。 这样做意味着你将无法从数据库还原这些迁移,并且可能会破坏后续迁移所做的假设。

列出所有迁移

cli:dotnet ef migrations list
vs:Get-Migration

回滚

上面创建迁移后执行Update-Database,可以将迁移应用到数据库。
Update-Database后面加参数表示回滚到指定迁移文件,如Update-Database InitialCreate,表示数据库回滚到InitialCreate这个迁移,脚本不会有变化

生成迁移脚本(Script-Migration

上面说的应用迁移Update-Database,只适用于开发环境,线上环境应该生成迁移脚本,并手动执行
Script-Migration命令用来生成SQL脚本,并不执行,需要手动执行
Script-Migration可以生成D版本到F版本之间的SQL脚本

Script-Migration D F

生成D版本到最新版本的SQL脚本:

Script-Migration D

重置所有迁移

在某些极端情况下,可能需要删除所有迁移并重新开始。 这可以通过删除 迁移 文件夹并删除数据库来轻松完成;此时,你可以创建新的初始迁移,其中将包含整个当前架构。
还可以重置所有迁移并创建单个迁移,而不会丢失数据。 这有时称为 "squashing",包括一些手动工作:

  • 删除 Migrations 文件夹
  • 创建新迁移并为其生成 SQL 脚本
  • 在数据库中,删除迁移历史记录表中的所有行
  • 将单个行插入到迁移历史记录中,记录已应用的第一个迁移,因为表已经存在。 insert SQL 是上面生成的 SQL 脚本中的最后一个操作。

自定义迁移文件

尽管 EF Core 通常会创建准确的迁移,但应始终查看代码,并确保其对应于所需的更改;

列重命名

在重命名属性时需要自定义迁移。 例如,如果将属性重命名 Name 为 FullName ,EF Core 将生成以下迁移:

migrationBuilder.DropColumn(
    name: "Name",
    table: "Customers");

migrationBuilder.AddColumn(
    name: "FullName",
    table: "Customers",
    nullable: true);

如果以上迁移按原样应用,则所有客户名称都将丢失。 若要重命名列,请将上面生成的迁移替换为以下内容:

migrationBuilder.RenameColumn(
    name: "Name",
    table: "Customers",
    newName: "FullName");

当某个操作可能会导致数据丢失(例如删除某列),搭建迁移基架过程将对此发出警告。 如果看到此警告,务必检查迁移代码的准确性。

添加原始SQL

重命名列可以通过内置 API 来实现,在许多情况下,这是不可能的。 例如,我们可能希望将现有的 FirstName 和属性替换为 LastName 一个新的 FullName 属性。 EF Core 生成的迁移如下:

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

migrationBuilder.AddColumn(
    name: "FullName",
    table: "Customer",
    nullable: true);

这会导致不需要的数据丢失。 为了传输旧列中的数据,我们会重新排列迁移并引入原始 SQL 操作,如下所示:

migrationBuilder.AddColumn(
    name: "FullName",
    table: "Customer",
    nullable: true);

migrationBuilder.Sql(
@"
    UPDATE Customer
    SET FullName = FirstName + ' ' + LastName;
");

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");