将 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的主要内容,如果未能解决你的问题,请参考以下文章