将 EF 迁移合并到新的 InitialCreate

Posted

技术标签:

【中文标题】将 EF 迁移合并到新的 InitialCreate【英文标题】:Consolidating EF migrations into new InitialCreate 【发布时间】:2012-11-02 23:45:55 【问题描述】:

我使用 EF 迁移已经有一段时间了,我的项目中有 100 多个迁移文件。我想在继续之前将这些合并到一个迁移中 - 即,我想用一个新版本替换现有的 InitialCreate 迁移,该版本将我所有的后续更改都考虑在内,这样我就可以删除所有其他迁移文件。

如果我不担心丢失数据库中的所有数据,我很容易做到这一点,但我是。

我怎样才能做到这一点,同时保持所有数据完好无损,并保持通过运行 Update-Database(我认为使用 the approach outlined by Julie Lerman 不可能)从头开始(没有数据)重新创建数据库的能力?

【问题讨论】:

我鼓励您为此submit a feature request。我认为“压缩”迁移是在工具中启用的一个很好的场景。 如果你可以假设你不需要向下,你能把所有向上的过程结合起来吗? 我也有同样的“问题”——现在有官方解决方案吗? 【参考方案1】:

考虑阅读 Rick Strahl 的这篇精彩文章: https://weblog.west-wind.com/posts/2016/jan/13/resetting-entity-framework-migrations-to-a-clean-slate

基本上,解决方案并不简单,需要的不仅仅是将所有迁移重置为一个 因为您有两个场景需要适合 ONE 迁移类:

创建一个新数据库 => 迁移类应该包含每个表创建 我的数据库已经是最新的 => 我需要一个空的迁移类

解决方案: 这个过程的想法基本上是这样的:数据库和 EF 架构是最新的,并且正是您想要的方式,所以我们将删除现有的迁移并创建一个新的初始迁移。

总的来说,执行此操作的步骤是:

从数据库中删除 _MigrationHistory 表 删除项目的 Migrations 文件夹中的各个迁移文件 在包管理器控制台中启用迁移 在 PMC 中添加迁移初始 注释掉初始迁移中Up方法里面的代码 PMC 中的更新数据库(除了创建迁移之外什么都不做 条目)在 Initial 方法中删除 cmets 你现在基本上已经 将架构重置为最新版本。 在所需数据库上执行注释掉的迁移后,取消注释迁移代码

【讨论】:

【参考方案2】:

如果您不关心保留此迁移,我所做的是删除迁移文件夹中的所有内容,然后在连接字符串中定位一个新数据库(或传入一个新数据库)。之后,您可以运行 add-migration 命令:

add-migration InitialCreate

它应该为你创建迁移。

【讨论】:

如果我以新数据库为目标,我将丢失所有数据。对吗? 这只是创建单个迁移文件.. 之后您可以定位您的主数据库。您这样做的原因是,当您进入生产(或移动目标)时,只有一次迁移,对吗? 如果您随后以主数据库为目标,它将尝试运行新的合并迁移并失败,因为所有表都已存在。 这是一种有点缺陷的方法,因为它只会从 EF 可以从您的代码中扣除的内容创建迁移。您在之前的迁移中自定义配置的所有内容都将丢失,例如自定义检查约束、过滤索引等。 @Pete 它有缺陷,是的。您可以通过删除__MigrationHistory 系统表来克服它。但是 EF never 将保留索引和其他内容。您必须自己编写,因此您不会删除自己编写的代码。【参考方案3】:

以下过程的好处是无需对 DB 进行任何操作,__MigrationHistory 可以保持原样。如果您有多个具有不同版本结构的不同环境,它也将起作用 - 只要您有要匹配的分支。

我将最后一次迁移变成了初始迁移。诀窍是使用最旧版本的代码和正在使用的数据库,用新的初始迁移替换其上次迁移并删除所有以前的迁移。较新的分支保留较新的迁移,因此在合并到旧分支后这些迁移仍然有效。

所以从 OLDEST 分支开始——通常是 PROD——然后做:

    删除除最后一次迁移之外的所有迁移 删除上次迁移中“Up”和“Down”方法中的迁移代码 将上次迁移的构建操作更改为“无”以让 EF 忽略它 将活动连接更改为指向本地 DB 数据库。 确保此本地 DB 数据库不存在 添加迁移初始 将创建的“初始”迁移中的向上和向下代码复制到最后一次迁移 删除初始迁移 将上次迁移的构建操作更改回“编译” 入住 向上合并更改 在 LocalDB DB 上的 DEV 分支中进行测试 - 它应该执行新的初始迁移以及后续迁移,没有问题 在最新数据库的主分支中测试 - 它不应该做任何事情

仅当您不向迁移中添加 EF 自身不执行的内容时,上述注意事项才有效。例如。如果您添加数据库视图等而不是新创建的迁移不会获得这些,它只会获得 EF 根据您的代码生成的脚本。

【讨论】:

【参考方案4】:

删除所有迁移或重新生成它们都有缺点,因此我们采取了一种方法,将所有旧迁移合并。

它需要一些脚本。你在这里阅读了详细信息https://www.bokio.se/engineering-blog/how-to-squash-ef-core-migrations/ 并在此处查看脚本https://github.com/bokio/EFCoreTools/tree/main/MigrationSquasher

不过,基本步骤如下(复制自博文):

我们的方法概述

    从旧迁移创建一个新的数据库(我们将使用 这个供以后比较) 找到合适的目标迁移 新的首字母(我们选择了一个大约 3 个月大的) 编写脚本到 将所有早期迁移的 Up() 方法合并到 Up() 一种新的迁移方法。我们忽略了 Down() 因为我们不使用它 用于旧迁移。 生成此迁移并将其添加到 项目。在我们的例子中,我们称之为 20200730130157_SquashedMigrations1.cs。我们使用了来自 我们选择的目标迁移。 生成第二次准备迁移 插入到迁移历史中 20200730130157_SquashedMigrations1.cs 已经运行。我们打电话给 这个 20200730130156_SquashedMigrations1_prep.cs。注意略 那个时间戳更小,以确保它在实际运行之前运行 迁移。 删除旧迁移 将我们的配置指向一个新的 数据库并运行迁移。 比较我们生成的架构 使用 Visual Studio 中的 Sql Schema Compare 相等。 完成工作 直到我们有相同的模式。这部分有点 很复杂,但我会回头再说。 合并和?(好的,我们确实运行了 在本地和临时数据库上进行更多测试)

我希望这对其他人有所帮助。 EF 团队正在考虑改进这个故事,所以如果您对您的要求有反馈,它可能会帮助他们现在发布 https://github.com/dotnet/efcore/issues/2174。

【讨论】:

【参考方案5】:

我们遇到了同样的问题。 我们找到的一般解决方案是

在 Nuget 包上存档旧的迁移/上下文(包括依赖项并使用不同的命名空间以避免冲突) 删除所有迁移并从头开始创建新的 Init (InitV2) 迁移。 更改我们应用程序的启动顺序: 如果数据库包含第一个旧的 Init 迁移,则 使用 Nuget 包迁移数据库以确保它是最新的 然后擦除 __EFMigrationHistory 表的内容并在表中插入新的迁移 然后在新上下文中使用标准 Migrate 方法 就是这样!

这个解决方案比较简单。它解决了所有情况

新数据库(将使用 InitV2) 旧数据库(将升级到最后一个 V1 迁移,然后升级到 v2 数据库的最后一个版本)

请注意,如果您在 v1 迁移中使用了自定义脚本/sql(...),则必须检查 v2 Init 迁移是否需要它。

为确保一切正常,我们从 v1 迁移创建了一个空数据库,从 v2 init 迁移创建了另一个数据库,并进行了架构和数据差异(使用 Visual Studio SQL Server 工具)

【讨论】:

以上是关于将 EF 迁移合并到新的 InitialCreate的主要内容,如果未能解决你的问题,请参考以下文章

七色花基本权限系统- 让EntityFramework Code First自动合并/迁移/数据初始化

Docker的镜像迁移到另一台服务器

将应用数据迁移到新的 IOS 应用

通过迁移将核心数据实体及其数据移动到新的核心数据模型文件中

如何将模板迁移到新的子目录?

将音频和视频轨道合并到新的 MediaStream 中