清除旧的Entity Framework Core迁移的推荐方法 [英] Recommended way to clean old Entity Framework Core migrations

查看:80
本文介绍了清除旧的Entity Framework Core迁移的推荐方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

After developing our application for a while we've accumulated quite a bit of EFCore database migrations. Since EFCore adds a snapshot of the entire db model to every migration, this code adds up quite a bit. After analysis about 80% of our compile time is spend on the migrations (compiling + Roslyn analyzers).

因此,现在该清理一些旧的迁移了!但是最好的方法是什么?似乎没有任何官方指导...

So it's time to clean up some old migrations! But what's the best way to do this? There doesn't seem to be any official guidance on it...

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

We don't need any rollbacks (we only roll forward), so that makes things more simple. We do need to support creating a database from scratch, and updating a database from the last few migrations.

我尝试过的操作:


  1. 最核心的选择似乎是删除所有迁移和模型快照,并创建一个新的初始迁移。尽管这很好,但似乎有些危险。使用这种方法,我们需要非常小心,使数据库架构的每个部分都成为代码模型的一部分。例如,我们遇到的一个极端情况是EFCore还不支持检查的约束。因此,我们在迁移中添加了检查约束,但未在代码模型中添加。因此,在创建新的初始迁移时,检查的约束不属于其中。

  1. The nuclear option seems to be to delete all migrations and the model snapshot, and creating a new initial migration. While this is fine, it seems a bit dangerous. With this approach we need to be very careful that every part of the database schema is part of the code model. One edge case we for example ran into is that EFCore doesn't support checked constraints yet. So we added a checked constraint in a migration, but not in the code model. So when creating a new initial migration, the checked constraint was not part of it.

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

As an experiment, I've tried to delete the model snapshot from all old migrations, since the snapshots are 90% of the code which cause the long compile time. I figured out, that EFCore only uses the snapshot as a compare tool to make a new migration. After deleting the snapshot, the old migrations were however no longer executed when they ran on a fresh database.

推荐答案

好吧,因为问了这个问题,我对此做了很多实验。

Okay, since asking this question I've experimented quite a bit with this.

目前看来,实现此目的的最佳方法是选项1。选项2会好得多,但要等到此EFCore功能已实现,对于我的用例而言,它确实不可行(支持现有的dbs进行迁移,并支持空的dbs)

It seems for now, the best way to accomplish this is option 1. Option 2 would be much better, but until this EFCore feature is implemented, it's not really doable for my use case (supporting existing dbs with migrations on them, and supporting empty dbs).

选项1也有一些我偶然发现的陷阱(也许还有更多我没有偶然发现的陷阱)。
这就是我的做法:

Option 1 also has a few pitfalls which I stumbled upon (maybe even more that I haven't stumbled upon). So this is how I did it:

创建新的初始迁移:


  1. 确保所有现有迁移都已应用到数据库。我们将创建一个新的初始迁移,因此尚未应用的迁移将丢失。

  2. 删除旧的EFCore迁移文件和数据库快照文件。

  3. 从数据库的当前状态创建新的初始迁移。 (例如,通过 dotnet ef迁移添加Initial-PostCleanup 。)

  1. Make sure all your existing migrations have been applied to your database. We'll create a new initial migration, so the migrations that haven't been applied will be lost.
  2. Delete your old EFCore migration files, and the database snapshot file.
  3. Create a new Initial migration from your database's current state. (For example via dotnet ef migrations add Initial-PostCleanup.)

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

This new migration is only compatible with new databases, since it will create all tables (and fail if any of the tables, constraints, etc. already exist). So now we're going to make this migration compatible with the existing database:


  1. 通过<$为新的初始迁移创建SQL脚本c $ c> dotnet ef迁移脚本-o script.sql 。

  2. 删除第一个事务(直到第一个 GO ),它会创建 __ EFMigrationsHistory 表:

  1. Create a SQL script for the new initial migration via dotnet ef migrations script -o script.sql.
  2. Remove the first transaction (until the first GO), which creates the __EFMigrationsHistory table:



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




  1. 删除最后一个事务,该事务将新条目插入 __ EFMigrationsHistory 表中:

  1. Remove the last transaction, that inserts the new entry in the __EFMigrationsHistory table:



INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190704144924_Initial-PostCleanup', N'2.2.4-servicing-10062');

GO




  1. 删除 GO 命令,因为我们会将创建脚本放入IF语句中:

    替换 GO\r\n \r\n 什么都没有。

  2. 现在打开您的迁移文件(C#文件,而不是sql文件)并替换 Up 方法如下:

  1. Remove GO commands, since we will put the create script in an IF statement:
    Replace GO\r\n\r\n with nothing.
  2. Now open up you migration file (the C# file, not the sql file) and replace the Up method with the following:



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
");
}

完成!一切都应该正常工作!

Done! Everything should work now!

请确保比较数据库架构以及新数据库之前和之后的数据。如果您的EF代码模型不属于新数据库,则不包括在内的所有内容。

Be sure to compare the database schema, and data before and after for the new database. Everything that's not part if your EF Code model is not part of the new database.

这篇关于清除旧的Entity Framework Core迁移的推荐方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆