Jul*_*anR 44 c# migration collaboration entity-framework ef-migrations
我们有多个开发人员在使用Entity Framework 5.0的项目上工作.每个开发人员都使用自己的本地SQL 2012数据库,这样他就可以开发和测试而不会妨碍其他人.
起初,我们使用了自动迁移和基于代码的迁移的混合体.这根本不起作用,所以我们决定禁用自动迁移,只允许基于代码.我应该补充一点,我们再次启动了一个干净的数据库而没有_MigrationsHistory
来自所有自动迁移的"损坏" .
所以现在的工作流程是:
add-migration <Name>
将其应用于他的数据库update-database
.到目前为止,这运作良好.然而,在今天之前,通常只有我做了迁移而其他人应用了它们.但今天有来自三个开发人员的迁移.我刚刚完成了这些迁移,做了一件update-database
好事.
我也对自己的数据模型进行了更改,但是在结束时update-database
它给了我一个警告,我仍然没有更新,所以我做了add-migration <my migration>
.但是,当它支持迁移时,它给了我已经应用到数据库的所有迁移的更改.所以:它试图删除已经删除的列,尝试创建一个已经存在的表,等等.
怎么可能?我的假设是EF只是检查_MigrationsHistory
表格并找出表格中没有的迁移,并按名称的时间戳顺序应用这些迁移.但显然不是,因为即使我撤消自己的更改并且我有一个干净的环境,它仍然抱怨我的数据库与模型不同步.但我只是将这些更改删除并应用到我的数据库中.它是同步的.我也可以看到我刚才在_MigrationsHistory
表格中应用的迁移.
我唯一能想到的是我在一个不会导致数据库更改的数据模型中添加了一个属性(我List<X>
在数据模型中添加了一个Y,其中X是一对多关系中的多个.这不会导致数据库更改,因为X已经有一个外键到Y).可能是吗?如果是这样,那真的很脆弱,因为没有办法为此添加迁移,因为没有数据库更改,我也不知道如何解决这个问题.
我不知道如何处理这个问题,因为我当然可以编辑它所支撑的内容并删除已经应用于我的数据库的所有内容.但那又怎样?我检查它然后其他一些开发人员得到相同的消息,即使他的数据库不适用于我的新更改,支持他自己的更改,获取相同的无意义脚手架,编辑它,检查它然后下一个开发者得到它.它变成了一个恶性循环,与我们使用自动迁移时的情况类似,我认为我们已经通过切换到基于代码的方式来解决这个问题.我现在不能相信做正确的事情,这样做是一场噩梦.
我也尝试过添加我从同事那里逐一删除的迁移,update-database -t:201211091112102_<migrationname>
但无济于事.它仍然给我错误的脚手架.
那么我们在这里做错了什么,或者EF根本不是为这样的协作而构建的?
UPDATE
我创建了一个可重现的测试用例,虽然为了模拟这个多用户/多数据库场景,它有点冗长的舞蹈.
https://github.com/JulianR/EfMigrationsTest/
有上述项目时重现的步骤(这些步骤也出现在代码中):
以上是模拟三个用户,其中用户1进入他的数据库,另外两个用户也使用他的初始化来创建他们的数据库.然后,用户2和用户3都对数据模型进行自己的更改,并将其与应用更改所需的迁移一起添加到源控件.然后,用户1拉动用户2和3的更改,而用户1也自己对数据库进行了更改.然后,用户1调用update-database
以应用用户2和3的更改.然后,他自己进行迁移,然后错误地将用户2或3的更改添加到脚手架迁移,这会在应用于用户1的数据库时导致错误.
您需要像解决代码冲突一样手动解决迁移冲突。如果您进行更新并且有新的迁移,则需要确保最后一次迁移背后的元数据与当前模型匹配。要更新迁移的元数据,请为其重新发出Add-Migration命令。
例如,在您的方案中的步骤17(更新数据库)之前,应发出以下命令
Add-Migration M2
Run Code Online (Sandbox Code Playgroud)
这将更新元数据,使其与当前模型同步。现在,当您尝试添加M3时,它应该为空白,因为您没有进行任何进一步的模型更改。
选项1:添加空白的“合并”迁移
- 确保本地代码库中任何待处理的模型更改已写入迁移中。此步骤可确保您在生成空白迁移时不会错过任何合法的更改。
- 与源代码管理同步。
- 运行Update-Database以应用其他开发人员已签入的所有新迁移。**注意:****如果Update-Database命令没有收到任何警告,则其他开发人员也没有新的迁移,并且存在无需执行任何进一步的合并。
- 运行Add-Migration –IgnoreChanges(例如Add-Migration Merge –IgnoreChanges)。这将生成具有所有元数据(包括当前模型的快照)的迁移,但是将忽略在将当前模型与上次迁移中的快照进行比较时检测到的任何更改(这意味着您将获得空白的Up和Down方法)。
- 继续开发,或提交给源代码控制(当然是在运行单元测试之后)。
选项2:在上一次迁移中更新模型快照
- 确保本地代码库中任何待处理的模型更改已写入迁移中。此步骤可确保您在生成空白迁移时不会错过任何合法的更改。
- 与源控件同步。
- 运行Update-Database以应用其他开发人员已签入的所有新迁移。**注意:****如果Update-Database命令没有收到任何警告,则其他开发人员也没有新的迁移,并且存在无需执行任何进一步的合并。
- 运行Update-Database –TargetMigration(在我们一直遵循的示例中,这将是Update-Database –TargetMigration AddRating)。这将使数据库恢复到第二次迁移的状态-有效地“取消应用”来自数据库的最后一次迁移。**注意:****必须执行此步骤,以使其安全地编辑迁移的元数据,因为元数据也存储在数据库的__MigrationsHistoryTable中。这就是为什么仅在上次迁移仅在本地代码库中时才应使用此选项的原因。如果其他数据库应用了上一次迁移,则您还必须回滚它们并重新应用上一次迁移以更新元数据。
- 运行Add-Migration(在我们一直遵循的示例中,这类似于Add-Migration 201311062215252_AddReaders)。**注意:****您需要包括时间戳记,以便迁移知道您要编辑现有迁移,而不是搭建新迁移。这将更新上一次迁移的元数据以匹配当前模型。命令完成时,您将收到以下警告,但这正是您想要的。“仅重新移植了用于迁移的设计器代码'201311062215252_AddReaders'。要重新搭建整个迁移过程,请使用-Force参数。”
- 运行Update-Database以将更新的元数据重新应用到最新的迁移中。
- 继续开发,或提交给源代码控制(当然是在运行单元测试之后)。
MSDN在这方面有一篇很棒的文章。请通过它。