问题描述
我们有多个开发人员在使用Entity Framework 5.0的项目上工作。每个开发人员使用自己的本地SQL 2012数据库,以便他可以开发和测试,而不会妨碍他人。
We have multiple developers working on a project that uses Entity Framework 5.0. Every developer uses his own local SQL 2012 database so he can develop and test without impeding others.
首先,我们使用了自动迁移和基于代码的迁移的混合。这根本不行,所以我们决定禁用自动迁移,并且只允许基于代码。我应该补充说,我们再次启动了一个干净的数据库,而没有所有自动迁移的损坏 _MigrationsHistory
。
At first, we used a hybrid of automatic migrations and code-based migrations. That didn't work well at all so we decided to disable automatic migrations and to only allow code-based. I should add that we started again with a clean database without a 'corrupted' _MigrationsHistory
from all the automatic migrations.
所以现在的工作流程是:
So now the workflow is:
- 开发人员更改他的数据模型
-
添加迁移< Name>
并使用update-database
将其应用到他的数据库。 - 检查数据模型更改和迁移到Git。
- 另一位开发人员拉,接收更改并将其应用于他的数据库。
- Developer changes his datamodel
- Does
add-migration <Name>
and applies it to his database withupdate-database
. - Checks in the datamodel change and the migration into Git.
- Another developer pulls, receives the changes and applies it to his database.
,这个效果很好。然而在今天之前,通常只是我做了移民,其他人应用了他们。但今天有三名开发商迁移。我只是把这些迁移,做了一个更新数据库
这是罚款。
So far, this worked well. However before today it was usually just me who made the migrations and the others applied them. But today there were migrations from three developers. I just pulled those migrations, did an update-database
which went fine.
我还对我自己的数据模型进行了更改,但是在$ code> update-database add-migration<我的迁移> 。然而当它支架迁移时,它给了我已经应用到数据库的所有迁移的变化。所以:它试图删除已经被删除的列,尝试创建一个已经存在的表等。
I also had a change to my own datamodel however so at the end of the update-database
it gave me a warning that I still wasn't up to date so I did add-migration <my migration>
. However when it scaffolded the migration, it gave me the changes of all the migrations I had already applied to the database. So: it tried to drop columns that had already been dropped, tried to create a table that already existed, etc.
这怎么可能?我的假设是,EF将只是检查 _MigrationsHistory
表,并找出哪些迁移不存在于表中,然后按照时间戳排序的名字。但显然不是,因为即使我撤消自己的更改,我有一个干净的环境,它仍然抱怨我的数据库不是与模型同步。但是我只是将这些更改拖到我的数据库中。它 同步。我可以看到我刚刚在 _MigrationsHistory
表中应用的迁移。
How can that be? My assumption was that EF would just check the _MigrationsHistory
table and find out which migrations weren't present in the table yet and apply those one by one ordered by the timestamp that's part of the name. But apparently not, because even when I undo my own changes and I have a clean environment it still complains my database isn't in sync with the model. But I just pulled those changes and applied them to my database. It is in sync. I can see the migrations that I just applied in the _MigrationsHistory
table too.
唯一可以想到的是我添加了一个不会导致数据库更改的数据模型的属性(我添加了一个 List< X>
到数据模型Y,其中X是一个这不会导致数据库更改,因为X已经具有Y的外键)。可以吗?如果是这样,那真的很脆弱,因为没有办法为此添加迁移,因为没有数据库更改,我不知道如何解决这个问题。
The only thing I can think of is that I added a property to a datamodel that wouldn't result in a database change (I added a List<X>
to datamodel Y where X is the many in the one-to-many relationship. This wouldn't result in a database change as X already had a foreign key to Y). Could that be it? If so, that's really fragile because there's no way to add a migration for that since there's no database change and I'm not sure how to fix this either.
我不知道如何处理这个,因为我当然可以编辑它的脚手架,并删除已经应用到我的数据库的一切。但那又是什么?我检查它,然后一些其他开发人员得到相同的消息,他的数据库不是最新的,即使在应用我的新更改后,脚手架他自己的更改,获得相同的废话脚手架,编辑它,检查,然后下一个开发者得到它。当我们使用自动迁移时,它变成了一个恶性循环,与我们所使用的类似,我认为我们已经通过切换到基于代码的方式来修复。我现在不能信任做正确的事情,这是一个恶梦,像这样工作。
I'm not sure how to deal with this, because I can of course just edit what it scaffolded and remove everything that has already been applied to my database. But then what? I check it in and then some other developer gets the same message that his database isn't up to date even after applying my new changes, scaffolds his own changes, gets the same nonsense scaffolding, edits it, checks it in and then the next developer gets it. It becomes a vicious circle and a similar one to what we had when we used automatic migrations and I thought we had fixed that by switching to code-based only. I can't trust it right now to do the right thing and it's a nightmare to work with like this.
我还试过添加我从我的同时使用 update-database -t:201211091112102_< migrationname>
,但无效。它仍然给我错误的脚手架。
What I also tried is adding the migrations I pulled from my coworkers one by one with update-database -t:201211091112102_<migrationname>
but to no avail. It still gives me the erroneous scaffold.
那么我们在这里做错了什么,还是EF根本不是为这样的协作而建立的?
So what did we do wrong here, or is EF simply not built for collaboration like this?
更新
我创建了一个可重复的测试用例,它有点为了模拟这个多用户/多数据库场景,长时间的舞蹈。
I created a reproducible test case, it's a bit of a lengthy dance though in order to simulate this multi user/multi database scenario.
当您有上述项目时,重现步骤(这些步骤也存在)在代码中):
Steps to reproduce when you have the above project (these steps are also present in the code):
- add-migration Init
- update-database(在数据库'TestDb ')
- 将连接字符串更改为指向TestDb1
- TestDb1上的update-database
- 取消注释属性Foo在课程测试
- 添加迁移M1添加属性Foo到TestDb1
- 再次注释出Test.Foo
- 将连接字符串更改为指向TestDb2
- 从项目中排除迁移M1,因此不适用于TestDb2
- 在课堂上取消注释属性栏测试
- update-database将Init迁移应用于TestDb2
- 添加迁移M2以将属性栏添加到TestDb2
- 将连接字符串更改为指向原始TestDb
- 将迁移M1再次包含在项目中
- 在课程测试中取消注释属性Foo
-
- 取消注释属性SomeInt on class Test
- update-database
- 添加迁移M3
- update-database,因为M3尝试将列Foo添加到已经由迁移M1添加的数据库TestDb中。获取错误。
- add-migration Init
- update-database (on database 'TestDb')
- Change connection string to point to TestDb1
- update-database on TestDb1
- Uncomment property Foo on class Test
- add-migration M1 to add property Foo to TestDb1
- Comment out Test.Foo again
- Change connection string to point to TestDb2
- Exclude migration M1 from project so it doesn't get applied to TestDb2
- Uncomment property Bar on class Test
- update-database to apply Init migration to TestDb2
- add-migration M2 to add property Bar to TestDb2
- Change connection string to point to the original TestDb again
- Include migration M1 into the project again
- Uncomment property Foo on class Test
- Uncomment property SomeInt on class Test
- update-database
- add-migration M3
- update-database, get an error because M3 tries to add column Foo to database TestDb which was already just added by migration M1.
上面是模拟三个用户,其中用户1在他的数据库中,另外两个用他的初始化来创建他们的数据库。然后,用户2和用户3都对数据模型进行自己的更改,并将其添加到源控件以及应用更改所需的迁移。然后用户1拉动用户2和3的更改,而用户1也自己更改了数据库。然后,用户1调用 update-database
来应用用户2和3的更改。然后他支架自己的迁移,然后将用户2或3的更改错误地添加到脚手架迁移在应用于用户1的数据库时会导致错误。
The above is to simulate three users, where user 1 inits his database, the other two use his initialization to create their database as well. Then user 2 and user 3 both make their own change to the datamodel and add it to source control together with the migrations needed to apply the changes. Then user 1 pulls the changes of user 2 and 3 while user 1 has also made a change to the database himself. Then user 1 calls update-database
to apply the changes of user 2 and 3. He then scaffolds his own migration which then erroneously adds a change from user 2 or 3 to the scaffolded migration which causes an error when applied to user 1's database.
推荐答案
您需要手动解决迁移冲突,就像代码冲突一样。如果您更新并且有新的迁移,则需要确保上一次迁移后面的元数据符合当前模型。要更新迁移的元数据,请重新发出Add-Migration命令。
You need to manually resolve migration conflicts just like you would code conflicts. If you update and there are new migrations, you need to ensure that the metadata behind the last migration matches the current model. To update the metadata of the migration, re-issue the Add-Migration command for it.
例如,在您的方案中的第17步(更新数据库)之前,您应该发出以下命令
For example, before step 17 (Update-Database) in your scenario, you should issue the following command
Add-Migration M2
这将更新元数据,使其与当前模型同步。现在,当您尝试添加M3时,它应该是空白的,因为您没有进一步改变模型。
This will update the metadata to bring it in sync with your current model. Now when you try and add M3, it should be blank since you have not made any further model changes.
这篇关于在协作环境中实体框架中的迁移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!