当Update-database返回以下消息时,如何使EF与代码同步而不丢失数据
错误消息:System.Data.SqlClient.SqlException(0x80131904):数据库中已存在名为“'的对象。
我最初写这个作为一个自我回答的问题,因为我曾经和一些同事一起努力解决问题,但不幸的是,我的答案被删除了,我无法恢复。
由于人们试图“清理”旧的迁移,我怀疑这种情况会发生几次,我想我会用一步一步的说明来记录它。
我们发现自己的情况描述 :我们无法创建新的本地数据库,因为init脚本不完整,并且无法将更新应用于生产数据库,因为迁移脚本会创建已存在的表。而且,我们不想删除生产数据。
症状 :无法运行Update-Database,因为它正在尝试运行创建脚本,并且数据库已经具有相同名称的表。
错误消息:System.Data.SqlClient.SqlException(0x80131904):数据库中已存在名为“'的对象。
问题背景 :要更详细地了解这一点,我建议您观看这里引用的两个视频: https : //msdn.microsoft.com/en-us/library/dn481501(v = vs133).aspx
总而言之,EF根据数据库中名为dbo .__ MigrationHistory的表,了解当前数据库所处位置与代码所在位置的对比情况。当它查看Migration Scripts时,它会尝试使用脚本重新构建它最后的位置。如果它不能,它只是尝试按顺序应用它们。这意味着,它会返回到初始创建脚本,如果您查看UP命令的第一部分,它将是发生错误的表的CreeateTable。
解决方案 :我们需要做的是欺骗EF认为当前数据库是最新的,而“不”应用这些CreateTable命令,因为生产数据库已经存在。设置生产数据库后,我们仍然需要能够创建本地数据库。
步骤1:生产数据库清理首先,备份生产数据库。在SSMS中,右键单击数据库,选择“任务>导出数据层应用程序...”并按照提示进行操作。打开生产数据库并删除/删除dbo .__ MigrationHistory表。
步骤2:本地环境清理打开迁移文件夹并将其删除。我假设如果有必要你可以从git中取回所有这些。
步骤3:重新创建初始化在程序包管理器中,运行“启用 - 迁移”(如果您有多个上下文,EF将提示您使用-ContextTypeName)。运行“Add-Migration Initial -verbose”。这将创建初始脚本,以便根据当前代码从头开始创建数据库。如果您在之前的Configuration.cs中有任何种子操作,那么将其复制。
第4步:欺骗EF此时,如果我们运行Update-Database ,我们将收到原始错误。因此,我们需要欺骗EF认为它是最新的,而不运行这些命令。因此,在刚刚创建的初始迁移中进入Up方法并将其全部注释掉。
步骤5:更新数据库如果没有代码在Up进程上执行,EF将创建dbo .__ MigrationHistory表,其中包含正确的条目,表明它正确运行了此脚本。如果你愿意,去看看吧。现在,取消注释该代码并保存。如果要检查EF是否认为它是最新的,可以再次运行Update-Database 。它不会使用所有CreateTable命令运行Up步骤,因为它认为它已经完成了。
第6步:确认EF实际上是最新的如果您的代码尚未应用迁移,这就是我所做的......
运行“Add-Migration MissingMigrations”这将创建一个空脚本。因为代码已经存在,实际上有正确的命令在初始迁移脚本中创建这些表,所以我只是将CreateTable和等效的drop命令切换为Up和Down方法。
现在,再次运行Update-Database并观察它执行新的迁移脚本,在数据库中创建相应的表。
第7步:重新确认并提交。构建,测试,运行。确保一切正在运行然后提交更改。
第8步:让团队的其他成员知道如何继续。当下一个人更新时,EF将不知道它之前运行的脚本不存在的原因。但是,假设本地数据库可以被吹走并重新创建,这一切都很好。他们需要删除他们的本地数据库并再次添加从EF创建它。如果他们有本地更改和挂起的迁移,我建议他们再次在master上创建他们的数据库,切换到他们的功能分支并从头开始重新创建这些迁移脚本。