将EF迁移整合到新的InitialCreate中

时间:2012-11-14 13:14:29

标签: entity-framework entity-framework-5 ef-migrations

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

如果我不关心丢失数据库中的所有数据,我很容易这样做,但我是。

如何通过运行Update-Database(我认为使用the approach outlined by Julie Lerman无法实现)来保持所有数据的完整性并保留从头开始重新创建数据库(无数据)的能力?< / p>

5 个答案:

答案 0 :(得分:16)

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

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

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

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

总之,执行此操作的步骤如下:

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

答案 1 :(得分:10)

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

add-migration InitialCreate

它应该为你创建迁移。

答案 2 :(得分:2)

下面的过程的好处是无需对数据库做任何事情,__ MigrationHistory可以保持原样。如果您具有多个具有不同版本结构的环境,那么它也将起作用-只要您具有匹配的分支。

我将最后一次迁移转换为初始迁移。诀窍是使用所使用的代码和数据库的最旧版本,用新的初始迁移替换其最后的迁移,并删除所有先前的迁移。较新的分支机构保留较新的迁移,因此在合并到较旧的分支机构后这些分支仍将起作用。

因此从OLDEST分支开始-通常是PROD,然后执行以下操作:

  1. 删除除上一次迁移外的所有内容
  2. 在上次迁移中同时删除“ Up”和“ Down”方法中的迁移代码
  3. 将上一次迁移的构建操作更改为“无”,以使EF忽略它
  4. 更改活动连接以指向本地数据库数据库。
  5. 确保此本地数据库数据库不存在
  6. 添加迁移初始
  7. 将创建的“初始”迁移中的上下代码复制到上一次迁移
  8. 删除初始迁移
  9. 将上一次迁移的构建操作更改回“编译”
  10. 签入
  11. 合并更改
  12. 在LocalDB DB的DEV分支中进行测试-它应进行新的初始迁移以及后续的迁移,而不会出现问题
  13. 在最新数据库的主分支上进行测试-它不应执行任何操作

仅当您不向EF本身不会做的迁移添加内容时,以上注释才有效。例如。如果您添加数据库视图等,那么新创建的迁移将无法获得这些视图,则只能获得EF根据您的代码生成的脚本。

答案 3 :(得分:1)

删除所有迁移或重新生成它们有缺点,因此我们采用了合并所有旧迁移的方法。

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

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

我们的方法概述

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

我希望这对其他人有帮助。 EF 团队正在考虑改进这个故事,因此如果您对自己的需求有反馈意见,可能会帮助他们立即发布https://github.com/dotnet/efcore/issues/2174

答案 4 :(得分:0)

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

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

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

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

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

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