50

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

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

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

4

5 回答 5

26

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

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

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

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

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

  • 从数据库中删除 _MigrationHistory 表
  • 删除项目的 Migrations 文件夹中的单个迁移文件
  • 在包管理器控制台中启用迁移
  • PMC 中的添加迁移初始值
  • 注释掉 Initial Migration 中 Up 方法内的代码
  • PMC 中的更新数据库(除了创建迁移条目什么都不做) 删除 Initial 方法中的注释 您现在基本上已将架构重置为最新版本。
  • 在所需数据库上执行注释掉的迁移后,取消注释迁移代码
于 2016-10-06T12:48:29.173 回答
14

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

add-migration InitialCreate

它应该为您创建迁移。

于 2012-11-14T14:37:14.893 回答
2

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

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

所以从 OLDEST 分支开始 - 通常是 PROD - 并执行以下操作:

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

上面的注释仅在您不向迁移中添加 EF 自身不执行的内容时才有效。例如,如果您添加数据库视图等,那么新创建的迁移将不会获得这些,它只会获得 EF 根据您的代码生成的脚本。

于 2018-08-14T12:16:36.843 回答
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

于 2021-01-14T16:19:06.820 回答
0

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

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

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

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

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

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

于 2021-06-04T10:18:14.500 回答