如何从Entity Framework中恢复噩梦 - 数据库已经有了同名的表

时间:2017-09-07 03:29:25

标签: entity-framework entity-framework-6 database-migration ef-migrations

当Update-database返回以下消息时,如何使EF与代码同步而不会丢失数据

  

错误消息:System.Data.SqlClient.SqlException(0x80131904):有   已经是一个名为''在数据库中。

1 个答案:

答案 0 :(得分:0)

我最初把这个写成一个自我回答的问题,因为我曾经和一些同事一起努力解决问题,但不幸的是,我的答案被删除了,我无法恢复。

由于这种情况我怀疑可能会发生多次,因为人们会尝试清理"旧的迁移,我以为我会用一步一步的说明来记录它。

我们发现自己的情况描述: 我们无法创建新的本地数据库,因为init脚本不完整,并且无法将更新应用于生产数据库,因为迁移脚本会创建已存在的表。而且,我们并不想删除生产数据。

症状:无法运行 更新数据库 ,因为它正在尝试运行创建脚本和数据库已经有了同名的表。

  

错误消息:System.Data.SqlClient.SqlException(0x80131904):有   已经是一个名为''在数据库中。

问题背景: 为了更详细地了解这一点,我建议您观看此处引用的两个视频: https://msdn.microsoft.com/en-us/library/dn481501(v=vs.113).aspx

总而言之,EF基于数据库中名为dbo .__ MigrationHistory的表,了解当前数据库所处位置与代码所在位置的对比情况。当它查看Migration Scripts时,它会尝试使用脚本重新构建它的最后位置。如果它不能,它只是尝试按顺序应用它们。这意味着,它将返回到初始创建脚本,如果您查看UP命令的第一部分,它将成为发生错误的表的CreeateTable。

解决方案:我们需要做的是让EF认为当前数据库是最新的,而不是"不是"应用这些CreateTable命令,因为生产数据库已存在。设置生产数据库后,我们仍然需要能够创建本地数据库。

第1步:生产数据库清理 首先,备份生产数据库。在SSMS中,右键单击数据库,选择"任务>导出数据层应用程序......"并按照提示操作。 打开生产数据库并删除/删除dbo .__ MigrationHistory表。

第2步:本地环境清洁 打开迁移文件夹并将其删除。我假设如果有必要,你可以从git中取回所有这些。

第3步:重新创建初始 在程序包管理器中,运行"启用 - 迁移" (如果您有多个上下文,EF将提示您使用-Co​​ntextTypeName)。 运行" Add-Migration Initial -verbose"。这将创建初始脚本,以便根据当前代码从头开始创建数据库。 如果您在之前的Configuration.cs中有任何种子操作,则将其复制到。

第4步:欺骗EF 此时,如果我们运行 更新数据库 ,我们就会收到原始错误。因此,我们需要让EF认为它是最新的,而不需要运行这些命令。因此,在刚刚创建的初始迁移中进入Up方法并将其全部注释掉。

第5步:更新数据库 如果没有代码在Up进程上执行,EF将使用正确的条目创建dbo .__ MigrationHistory表,以表明它正确运行了此脚本。如果你愿意,去看看吧。 现在,取消注释该代码并保存。 如果要检查EF是否认为其是最新的,则可以再次运行 更新数据库 。它不会使用所有CreateTable命令运行Up步骤,因为它认为它已经完成了。

第6步:确认EF实际上是最新的 如果你的代码还没有应用迁移,那就是我做的......

运行"添加迁移MissingMigrations" 这实际上会创建一个空脚本。因为代码已经存在,所以在初始迁移脚本中实际上有正确的命令来创建这些表,因此我只是将CreateTable和等效的drop命令切换为Up和Down方法。

现在,再次运行 Update-Database 并观察它执行新的迁移脚本,在数据库中创建相应的表。

第7步:重新确认并提交。 构建,测试,运行。确保一切正在运行,然后提交更改。

第8步:让团队的其他成员知道如何继续。 当下一个人更新时,EF不知道是什么击中它,因为它已经运行的脚本不存在之前。但是,假设本地数据库可以被吹走并重新创建,这一切都很好。他们需要删除他们的本地数据库并再次添加从EF创建它。如果他们有本地更改和待定迁移,我建议他们再次在master上创建他们的数据库,切换到他们的功能分支并从头开始重新创建这些迁移脚本。