我最初写这个是作为一个自我回答的问题,因为我和一些同事一样,已经为这个问题苦苦挣扎了一段时间,但不幸的是,我的答案被删除了,我无法恢复。
由于我怀疑这种情况可能会在人们尝试“清理”旧迁移时多次发生,所以我想我会用分步说明记录它。
我们所处的情况描述:
我们无法创建新的本地数据库,因为 init 脚本不完整,并且无法将更新应用到生产数据库,因为迁移脚本创建的表已经存在。而且,我们不想删除生产数据。
症状:无法运行 Update-Database,因为它正在尝试运行创建脚本,并且数据库已经有相同的表名字。
错误信息:System.Data.SqlClient.SqlException (0x80131904): 那里
已经是数据库中名为 '' 的对象。
问题背景:
要更详细地了解这一点,我建议您观看此处引用的两个视频:
https://msdn.microsoft.com/en-us/library/dn481501(v=vs.113).aspx
总而言之,EF 可以根据数据库中名为 dbo.__MigrationHistory 的表了解当前数据库所在的位置与代码所在的位置。当它查看迁移脚本时,它会尝试与脚本协调它最后的位置。如果不能,它只是尝试按顺序应用它们。这意味着,它会回到最初的创建脚本,如果您查看 UP 命令的第一部分,它将是发生错误的表的 CreeateTable。
解决方案:我们需要做的是让 EF 认为当前数据库是最新的,而“不”应用这些 CreateTable 命令,因为生产数据库已经存在。设置生产数据库后,我们仍然需要能够创建本地数据库。
第 1 步:清理生产数据库
首先,备份您的生产数据库。在 SSMS 中,右键单击数据库,选择“任务 > 导出数据层应用程序...”并按照提示进行操作。
打开您的生产数据库并删除/删除 dbo.__MigrationHistory 表。
第 2 步:本地环境清洁
打开您的迁移文件夹并将其删除。我假设你可以在必要时从 git 中得到这一切。
第 3 步:重新创建初始状态
在包管理器中,运行“Enable-Migrations”(如果您有多个上下文,EF 将提示您使用 -ContextTypeName)。
运行“添加迁移初始 -verbose”。这将创建初始脚本以根据当前代码从头开始创建数据库。
如果您在之前的 Configuration.cs 中有任何种子操作,请将其复制。
第 4 步:欺骗 EF
此时,如果我们运行 Update-Database,我们将得到原始错误。因此,我们需要在不运行这些命令的情况下让 EF 认为它是最新的。因此,进入您刚刚创建的 Initial migration 中的 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 上再次创建他们的数据库,切换到他们的功能分支并从头开始重新创建这些迁移脚本。