清理旧的 Entity Framework Core 迁移的推荐方法

Nic*_*ler 12 entity-framework entity-framework-core .net-core

在开发我们的应用程序一段时间后,我们已经积累了相当多的 EFCore 数据库迁移。由于 EFCore 为每次迁移添加了整个 db 模型的快照,因此这段代码加起来相当多。经过分析,我们大约 80% 的编译时间都花在了迁移上(编译 + Roslyn 分析器)。

所以是时候清理一些旧的迁移了!但最好的方法是什么?好像没有官方的指导...

我们不需要任何回滚(我们只向前滚),所以这让事情变得更简单。我们确实需要支持从头开始创建数据库,并从最近几次迁移中更新数据库。

我试过的:

  1. 核选项似乎是删除所有迁移和模型快照,并创建一个新的初始迁移。虽然这很好,但似乎有点危险。使用这种方法,我们需要非常小心,数据库模式的每个部分都是代码模型的一部分。例如,我们遇到的一种边缘情况是 EFCore 尚不支持检查约束。所以我们在迁移中添加了一个检查约束,而不是在代码模型中。因此,在创建新的初始迁移时,已检查的约束不是其中的一部分。

  2. 作为实验,我尝试从所有旧迁移中删除模型快照,因为快照是导致编译时间过长的代码的 90%。我发现,EFCore 仅使用快照作为比较工具来进行新的迁移。删除快照后,旧的迁移在新数据库上运行时不再执行。

那么有没有更好的方法来完成我想要的?

Nic*_*ler 8

好的,自从提出这个问题以来,我已经对此进行了很多实验。

目前看来,实现此目的的最佳方法是选项 1。选项 2 会好得多,但在实现此 EFCore 功能之前,它对我的​​用例来说并不是真正可行的(支持现有数据库并对其进行迁移,并支持空数据库)。

选项 1 也有一些我偶然发现的陷阱(可能还有更多我没有偶然发现的)。所以我是这样做的:

创建一个新的初始迁移:

  1. 确保您现有的所有迁移都已应用于您的数据库。我们将创建一个新的初始迁移,因此尚未应用的迁移将丢失。
  2. 删除旧的 EFCore 迁移文件和数据库快照文件。
  3. 从数据库的当前状态创建一个新的初始迁移。(例如通过dotnet ef migrations add Initial-PostCleanup.)

这种新迁移仅与新数据库兼容,因为它将创建所有表(如果任何表、约束等已经存在,则失败)。所以现在我们要使这个迁移与现有数据库兼容:

  1. 通过 为新的初始迁移创建 SQL 脚本dotnet ef migrations script -o script.sql
  2. 删除GO创建__EFMigrationsHistory表的第一个事务(直到第一个事务):
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
    CREATE TABLE [__EFMigrationsHistory] (
        [MigrationId] nvarchar(150) NOT NULL,
        [ProductVersion] nvarchar(32) NOT NULL,
        CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
    );
END;

GO
Run Code Online (Sandbox Code Playgroud)
  1. 删除在__EFMigrationsHistory表中插入新条目的最后一个事务:
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190704144924_Initial-PostCleanup', N'2.2.4-servicing-10062');

GO
Run Code Online (Sandbox Code Playgroud)
  1. 删除GO命令,因为我们将创建脚本放在 IF 语句中:
    替换GO\r\n\r\n为空。
  2. 现在打开您的迁移文件(C# 文件,而不是 sql 文件)并将该Up方法替换为以下内容:
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql(@"
DECLARE @migrationsCount INT = (SELECT COUNT(*) FROM [dbo].[__EFMigrationsHistory])
IF @migrationsCount = 0
BEGIN
    % PASTE YOUR EDITED SQL SCRIPT HERE %
END
");
}
Run Code Online (Sandbox Code Playgroud)

完毕!一切都应该现在工作!

请务必比较新数据库的数据库架构和前后数据。如果您的 EF 代码模型不属于新数据库的一部分,则不属于的所有内容。

  • 使用此解决方案时可能会遇到一个陷阱:您将失去数据库独立性,因为复制的 SQL 现在特定于您的数据库类型。 (2认同)
  • 任何原因为什么人们不只是 a.) 删除迁移 b.) 创建初始和 c.) 删除数据库表中 __migrationhistory 中除第一项以外的所有项目,并更新第一条记录以具有正确的名称和哈希,如中所述快照? (2认同)

Jai*_*ule 8

有点晚了,但我们在当前的项目中遇到了同样的问题。.Designer 内超过 400 个迁移和 600 万行代码。以下是我们如何解决这个问题的:

迁移项目.csproj

  <PropertyGroup>
     ...
     <DefaultItemExcludes Condition="'$(Configuration)' == 'Debug' ">$(DefaultItemExcludes);Migrations\**\*.Designer.cs</DefaultItemExcludes>
  </PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

这样,您不需要将迁移重置为清晰状态,也不需要删除 .Designer 文件。您始终可以通过任何必要的方式将配置更改为发布并使用.Designer 文件。