第四单元 管理数据库架构

发布时间 2023-12-11 20:20:55作者: 誉尚学教育

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

  1. 如果希望以 EF Core 模型为准,请使用迁移。 对 EF Core 模型进行更改时,此方法会以增量方式将相应架构更改应用到数据库,以使数据库保持与 EF Core 模型兼容(CodeFirst,小项目用这种)。

  2. 如果希望以数据库架构为准,请使用反向工程。 使用此方法,可通过将数据库架构反向工程到 EF Core 模型来生成相应的 DbContext 和实体类型(DbFirst,中大型项目建议使用)。

 

1. 数据迁移

在实际项目中,数据模型随着功能的实现而变化:添加和删除新的实体或属性,并且需要相应地更改数据库架构,使其与应用程序保持同步。 EF Core 中的迁移功能能够以递增方式更新数据库架构,使其与应用程序的数据模型保持同步,同时保留数据库中的现有数据。

简要地说,迁移的方式如下:

  • 当引入数据模型更改时,开发人员使用 EF Core 工具添加相应的迁移,以描述使数据库架构保持同步所需的更新。EF Core 将当前模型与旧模型的快照进行比较,以确定差异,并生成迁移源文件;文件可在项目的源代码管理中进行跟踪,如任何其他源文件。

  • 生成新的迁移后,可通过多种方式将其应用于数据库。 EF Core 在一个特殊的历史记录表中记录所有应用的迁移,使其知道哪些迁移已应用,哪些迁移尚未应用。

 

安装工具

首先,必须安装 EF Core 命令行工具

  • 我们通常建议使用 .NET Core CLI 工具,该工具适用于所有平台。

    # 安装
    dotnet tool install -g --version 6.0.4 dotnet-ef
    
    # 更新
    dotnet tool update --global dotnet-ef --version 6.0.7
    
    # 在将工具用于特定项目之前,需要将 Microsoft.EntityFrameworkCore.Design 添加到该项目中。
    dotnet add package Microsoft.EntityFrameworkCore.Design --version 6.0.4
    dotnet add package Microsoft.EntityFrameworkCore.Tools --version 6.0.4
    # 验证
    dotnet ef
    
    _/\__
                   ---==/    \\
             ___  ___   |.    \|\
            | __|| __|  |  )   \\\
            | _| | _|   \_/ |  //|\\
            |___||_|       /   \\\/\\
    
    Entity Framework Core .NET Command-line Tools 2.1.3-rtm-32065
    
    <Usage documentation follows, not shown.>

     

    常用选项

    选项Short说明
    --json   显示 JSON 输出。
    --context <DBCONTEXT> -c 要使用的 DbContext 类。 仅类名或完全限定命名的空间。 如果省略此选项,EF Core 将查找上下文类。 如果有多个上下文类,则此选项是必需的。
    --project <PROJECT> -p 目标项目的项目文件夹的相对路径。 默认值是当前文件夹。
    --startup-project <PROJECT> -s 启动项目的项目文件夹的相对路径。 默认值是当前文件夹。
    --framework <FRAMEWORK>   目标框架目标框架名字对象。 当项目文件指定了多个目标框架,并且你想要选择其中一个目标框架时,请使用此选项。
    --configuration <CONFIGURATION>   生成配置,例如 DebugRelease
    --runtime <IDENTIFIER>   要为其还原包的目标运行时的标识符。 有关运行时标识符 (RID) 的列表,请参阅 RID 目录
    --no-build   请勿生成项目。 旨在在生成处于最新状态时使用。
    --help -h 显示帮助信息。
    --verbose -v 显示详细输出。
    --no-color   请勿为输出着色。
    --prefix-output   具有级别的前缀输出。
  • 如果你更喜欢在 Visual Studio 内工作或你具有 EF6 迁移经验,还可以使用程序包管理器控制台工具

    # 安装
    Install-Package Microsoft.EntityFrameworkCore.Tools
    
    # 更新
    Update-Package Microsoft.EntityFrameworkCore.Tools
    
    # 验证安装
    Get-Help about_EntityFrameworkCore
    
    _/\__
                   ---==/    \\
             ___  ___   |.    \|\
            | __|| __|  |  )   \\\
            | _| | _|   \_/ |  //|\\
            |___||_|       /   \\\/\\
    
    ......

     

    通用参数

    下表显示了所有 EF Core 命令的通用参数:

    参数说明
    -Context <String> 要使用的 DbContext 类。 仅类名或完全限定命名的空间。 如果省略此参数,EF Core 将查找上下文类。 如果有多个上下文类,则此参数是必需的。
    -Project <String> 目标项目。 如果省略此参数,则包管理器控制台的默认项目将用作目标项目。
    -StartupProject <String> 启动项目。 如果省略此参数,则解决方案属性中的启动项目将用作目标项目。
    -Args <String> 传递给应用程序的参数。 已在 EF Core 5.0 中添加。
    -Verbose 显示详细输出。

创建第一个迁移

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
}

 

你现在已准备好添加第一个迁移! 指示 EF Core 创建名为 InitialCreate 的迁移:

.NET CLI

dotnet ef migrations add InitialCreate

 

VisualStudio

Add-Migration InitialCreate

 

 

EF Core 将在项目中创建一个名为“Migrations”的目录,并生成一些文件。 最好检查 EF Core 生成的内容,并在可能的情况下修改它,但现在我们跳过此操作。

创建数据库和架构

此时,可以让 EF 创建数据库并从迁移中创建架构。 可以通过以下操作实现这一点:

 

.NET CLI

dotnet ef database update

 

VisualStudio

Update-Database

 

就是这么回事 - 你的应用程序已准备好在新数据库上运行,你无需编写任何 SQL 代码。 请注意,这种应用迁移的方法非常适合本地开发,但不太适用于生产环境 - 有关详细信息,请参阅应用迁移页面

 

发展模型

几天后,系统会要求你将创建时间戳添加到博客。 你已完成针对应用程序的必要更改,模型现在如下所示:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedTimestamp { get; set; }
}

 

模型和生产数据库现在不同步,我们必须向数据库架构中添加一个新列。 让我们为此创建新迁移:

 

.NET CLI

dotnet ef migrations add AddBlogCreatedTimestamp

 

VisualStudio

Add-Migration AddBlogCreatedTimestamp

 

 

请注意,我们为迁移提供了一个描述性名称,以便以后更容易了解项目历史记录。

由于这不是项目的第一次迁移,EF Core 现在会在添加列之前将更新的模型与旧模型的快照进行比较;模型快照是 EF Core 在你添加迁移时生成的文件之一,并签入到源代码管理中。 基于该比较,EF Core 检测到已添加一列,并添加适当的迁移。

现在,你可以像以前一样应用迁移:

.NET CLI

dotnet ef database update

 

VisualStudio

Update-Database

 

请注意,这次 EF 检测到数据库已存在。 此外,在之前第一次应用迁移时,此事实记录在数据库中的特殊迁移历史记录表中;这允许 EF 自动仅应用新的迁移。

 

排除模型的各个部分

备注

EF Core 5.0 中已引入此功能。

有时,你可能希望引用其他 DbContext 中的类型(表)。 这可能会导致迁移冲突。 若要防止出现这种情况,请从 DbContext 之一的迁移中排除该类型。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}

 

 

命名空间

可以手动移动 Migrations 文件并更改其命名空间。 新建的迁移和上个迁移同级。 或者,可以在生成时指定目录,如下所示:

.NET CLI

dotnet ef migrations add InitialCreate --output-dir Your/Directory

 

VisualStudio

Add-Migration InitialCreate -OutputDir Your\Directory

 

在 EF Core 5.0 中,你还可以使用 -Namespace 独立于目录更改命名空间。

删除迁移

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

如果迁移已被应用(执行了 database update),则无法使用remove。

.NET CLI

dotnet ef migrations remove

 

VisualStudio

Remove-Migration

 

列出迁移

你可以列出现有的所有迁移,如下所示:

.NET CLI

dotnet ef migrations list

 

VisualStudio

Get-Migration

 

 

重置所有迁移

在某些极端情况下,可能需要删除所有迁移并重新开始。 这可以通过删除 Migrations 文件夹并删除数据库来轻松完成;此时,你可以创建一个新的初始迁移,其中将包含当前的整个架构。

你还可以重置所有迁移并创建单个迁移,而不会丢失数据。 此操作有时称为“更正”,涉及一些手动操作:

  • 删除 Migrations 文件夹

  • 创建新迁移并为其生成 SQL 脚本

  • 在数据库中,删除迁移历史记录表中的所有行

  • 在迁移历史记录中插入一行,以记录第一个迁移已经应用,因为表已经存在。 insert SQL 是上面生成的 SQL 脚本中的最后一个操作(在我们删除了Migrations文件夹中所有的迁移文件以及删除完_efmigrationshistory表中的记录之后,再执行一次migrations add 的命令,表示重新添加一条记录,然后不要执行database update 命令,最后再把刚刚迁移生成的记录添加至__efmigrationshistory 表中)。

警告

删除 Migrations 文件夹后,所有自定义迁移代码都将丢失。 若要保留任何自定义项,必须手动将其应用到新的初始迁移。

 

2. 应用迁移

添加迁移后,需要将其部署并应用到数据库。 有多种策略可用于执行此操作,其中一些更适合生产环境,而另一些更适合开发生命周期。

备注

无论部署策略是什么,都应检查生成的迁移并进行测试,然后再将其应用于生产数据库。 迁移可能会在意图是对列进行重命名时删除该列,或者在应用于数据库时因各种原因而失败。

SQL 脚本

建议通过生成 SQL 脚本,将迁移部署到生产数据库。 此策略的优点包括:

  • 可以检查 SQL 脚本的准确性;这一点很重要,因为将架构更改应用于生产数据库是一项可能导致数据丢失的潜在危险操作。

  • 在某些情况下,可以根据生产数据库的特定需求调整这些脚本。

  • SQL 脚本可以与部署技术结合使用,甚至可以在 CI 过程中生成。

  • SQL 脚本可以提供给 DBA,并且可以单独管理和存档。

基本用法

以下命令将生成一个从空白数据库到最新迁移的 SQL 脚本:

.NET CLI

dotnet ef migrations script

 

VisualStudio

Script-Migration

 

 

3. 反向工程

反向工程是基于数据库架构搭建实体类型类和 DbContext 类基架的过程。 可使用 EF Core 包管理器控制台 (PMC) 工具的 Scaffold-DbContext 命令或 .NET 命令行接口 (CLI) 工具的 dotnet ef dbcontext scaffold 命令执行这一过程。

先决条件

  • 在进行反向工程之前,需要安装 PMC 工具(仅限 Visual Studio)或 CLI 工具。 有关详细信息,请参阅链接。

  • 在要搭建基架的项目中安装 Microsoft.EntityFrameworkCore.Design 的 NuGet 包。

  • 还需要为要进行反向工程的数据库架构安装适当的数据库提供程序

连接字符串

该命令的第一个参数是指向数据库的连接字符串。 工具将使用此连接字符串来读取数据库架构。

引用和转义连接字符串的方式取决于用于执行命令的 shell。 有关详细信息,请参阅 shell 的文档。 例如,PowerShell 要求转义 $ 字符,而不是 \

.NET CLI

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer

 

VisualStudio

Scaffold-DbContext 'Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook' Microsoft.EntityFrameworkCore.SqlServer
 

 

指定表

默认情况下,将数据库架构中的所有表反向工程为实体类型。 可通过指定架构和表来限制对哪些表进行反向工程。

.NET CLI

--schema 选项可用于包含架构中的每个表,而 --table 可用于包含特定表。

若要包含多个表,请多次指定选项:

dotnet ef dbcontext scaffold ... --table Artist --table Album

 

VisualStudio

-Schemas 选项可用于包含架构中的每个表,而 -Tables 可用于包含特定表。

若要包含多个表,请使用数组:

Scaffold-DbContext ... -Tables Artist, Album

 

保留名称

默认情况下,表和列名已修正,以便更好地匹配类型和属性的 .NET 命名约定。 在 PMC 中指定 -UseDatabaseNames 开关或在 .NET Core CLI 中指定 --use-database-names 选项将禁用此行为,从而尽可能保留原始数据库名称。 无效的 .NET 标识符仍将被修正,而合成名称(如导航属性)仍将符合 .NET 命名约定。

 

DbContext 名称

默认情况下,已搭建基架的 DbContext 类名称将是后缀为 Context 的数据库名称。 若要指定不同名称,请在 PMC 中使用 -Context,在 .NET Core CLI 中使用 --context

目录和命名空间

实体类和 DbContext 类将搭建到项目的根目录中,并使用项目的默认命名空间。

.NET CLI

可使用 --output-dir 指定在其中为类搭建基架的目录,并且可使用 --context-dir 将 DbContext 类搭建到与实体类型类不同的目录中:

dotnet ef dbcontext scaffold ... --context-dir Data --output-dir Models

 

默认情况下,命名空间将是根命名空间加上项目根目录下任何子目录的名称。 但是,从 EFCore 5.0 开始,可使用 --namespace 覆盖所有输出类的命名空间。 还可使用 --context-namespace 仅覆盖 DbContext 类的命名空间:

dotnet ef dbcontext scaffold ... --namespace Your.Namespace --context-namespace Your.DbContext.Namespace

 

 

VisualStudio

可使用 -OutputDir 指定在其中为类搭建基架的目录,并且可使用 -ContextDir 将 DbContext 类搭建到与实体类型类不同的目录中:

Scaffold-DbContext ... -ContextDir Data -OutputDir Models

 

默认情况下,命名空间将是根命名空间加上项目根目录下任何子目录的名称。 但是,从 EFCore 5.0 开始,可使用 -Namespace 覆盖所有输出类的命名空间。 还可使用 -ContextNamespace 仅覆盖 DbContext 类的命名空间。

Scaffold-DbContext ... -Namespace Your.Namespace -ContextNamespace Your.DbContext.Namespace

 

 

配套视频链接:课程简介 (cctalk.com)