我们有多个开发人员正在开发一个使用 Entity Framework 5.0 的项目。每个开发人员都使用自己的本地 SQL 2012 数据库,因此他可以在不妨碍他人的情况下进行开发和测试。
起初,我们混合使用了自动迁移和基于代码的迁移。这根本不起作用,所以我们决定禁用自动迁移并只允许基于代码的迁移。我应该补充一点,我们从一个干净的数据库重新开始,而_MigrationsHistory
所有自动迁移都没有“损坏”。
所以现在的工作流程是:
- 开发人员更改他的数据模型
- 使用.
add-migration <Name>
将其应用于他的数据库update-database
。 - 检查数据模型更改并迁移到 Git。
- 另一个开发人员提取、接收更改并将其应用到他的数据库。
到目前为止,这运作良好。然而在今天之前,通常只有我进行迁移,其他人应用它们。但是今天有来自三个开发人员的迁移。我刚刚取消了那些迁移,做得update-database
很好。
我也对自己的数据模型进行了更改,但是在最后update-database
它给了我一个警告,说我仍然不是最新的,所以我做了add-migration <my migration>
。但是,当它为迁移搭建脚手架时,它给了我已经应用到数据库的所有迁移的更改。所以:它试图删除已经被删除的列,试图创建一个已经存在的表,等等。
这个怎么可能?我的假设是 EF 只会检查_MigrationsHistory
表并找出表中尚不存在哪些迁移,并按名称中的时间戳顺序逐一应用这些迁移。但显然不是,因为即使我撤消自己的更改并且我有一个干净的环境,它仍然会抱怨我的数据库与模型不同步。但我只是提取了这些更改并将它们应用到我的数据库中。它是同步的。我也可以看到我刚刚在_MigrationsHistory
表格中应用的迁移。
我唯一能想到的是我向数据模型添加了一个不会导致数据库更改的属性(我List<X>
向数据模型 Y 添加了一个,其中 X 是一对多关系中的多个。这不会导致数据库更改,因为 X 已经有 Y 的外键)。会是这样吗?如果是这样,那真的很脆弱,因为没有办法为此添加迁移,因为没有数据库更改,我也不知道如何解决这个问题。
我不确定如何处理这个问题,因为我当然可以编辑它所搭建的内容并删除已经应用于我的数据库的所有内容。但是然后呢?我签入它,然后其他一些开发人员收到相同的消息,即使在应用我的新更改后,他的数据库也不是最新的,搭建他自己的更改,获得相同的废话脚手架,编辑它,签入,然后下一个开发商明白了。它变成了一个恶性循环,与我们使用自动迁移时的情况类似,我认为我们已经通过切换到仅基于代码的方式解决了这个问题。我现在不能相信它会做正确的事情,像这样工作简直是一场噩梦。
我还尝试过添加我从同事那里提取的迁移,update-database -t:201211091112102_<migrationname>
但无济于事。它仍然给了我错误的脚手架。
那么我们在这里做错了什么,或者 EF 根本不是为这样的协作而构建的?
更新
我创建了一个可重现的测试用例,但为了模拟这种多用户/多数据库场景,这有点冗长。
https://github.com/JulianR/EfMigrationsTest/
当您拥有上述项目时重现的步骤(这些步骤也存在于代码中):
- 添加迁移初始化
- 更新数据库(在数据库“TestDb”上)
- 更改连接字符串以指向 TestDb1
- TestDb1 上的更新数据库
- 取消注释类 Test 上的属性 Foo
- add-migration M1 将属性 Foo 添加到 TestDb1
- 再次注释掉 Test.Foo
- 更改连接字符串以指向 TestDb2
- 从项目中排除迁移 M1,使其不会应用于 TestDb2
- 取消注释类 Test 上的属性 Bar
- 更新数据库以将初始化迁移应用到 TestDb2
- add-migration M2 将属性 Bar 添加到 TestDb2
- 更改连接字符串以再次指向原始 TestDb
- 再次将迁移 M1 包含到项目中
- 取消注释类 Test 上的属性 Foo
- 取消注释类 Test 上的属性 SomeInt
- 更新数据库
- 添加迁移 M3
- 更新数据库,因为 M3 尝试将 Foo 列添加到数据库 TestDb 中,该列已经由迁移 M1 添加。
以上是模拟三个用户,其中用户1初始化他的数据库,另外两个使用他的初始化来创建他们的数据库。然后用户 2 和用户 3 都对数据模型进行了自己的更改,并将其与应用更改所需的迁移一起添加到源代码管理中。然后用户 1 拉取用户 2 和 3 的更改,而用户 1 自己也对数据库进行了更改。然后用户 1 调用update-database
以应用用户 2 和 3 的更改。然后他构建自己的迁移,然后错误地将用户 2 或 3 的更改添加到脚手架迁移中,这在应用于用户 1 的数据库时会导致错误。