.net 实体框架代码优先:如何手动更新数据库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6618587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework Code-First: How to manually update the database?
提问by Mike
I've build a little WPF demo app which uses EF Code-First to save its data in a SQL CE 4.0 DB. It works fine unless I remove a property from a model object. For example, if I remove "HosteBy" from this class.....
我已经构建了一个小 WPF 演示应用程序,它使用 EF Code-First 将其数据保存在 SQL CE 4.0 DB 中。除非我从模型对象中删除属性,否则它工作正常。例如,如果我从这个类中删除“HosteBy”.....
public class Dinner
{
public int DinnerID { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public string Address { get; set; }
public string HostedBy { get; set; }
public virtual ICollection<RSVP> RSVPs { get; set; }
}
...it throws this exception:
...它抛出这个异常:
The model backing the 'NerdDinners' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.
自数据库创建以来,支持“NerdDinners”上下文的模型已更改。手动删除/更新数据库,或使用 IDatabaseInitializer 实例调用 Database.SetInitializer。例如,DropCreateDatabaseIfModelChanges 策略将自动删除并重新创建数据库,并可选择使用新数据为其播种。
The error persists even after removing the field "HosteBy" manually from the database. What am I missing here? Do I have to delete/truncate the db or is there another solution?
即使从数据库中手动删除字段“HosteBy”后,该错误仍然存在。我在这里缺少什么?我必须删除/截断数据库还是有其他解决方案?
回答by Chris Moschini
In the first scenario where you changed the Code First Model, before you went and modified the database manually, the answer is to open the (Nuget) Package Manager Console and type:
在您更改 Code First 模型的第一个场景中,在您手动修改数据库之前,答案是打开 (Nuget) 包管理器控制台并键入:
update-database -verbose
Except - because in this case you are removing a column this will report that it's about to delete something, and it won't delete anything without you explicitly saying that's OK. So you type:
除了 - 因为在这种情况下您正在删除一个列,这将报告它即将删除某些内容,并且如果您没有明确表示可以,它不会删除任何内容。所以你输入:
update-database -f -verbose
Now this will delete the column you had in your Model. -verbosesays to show you the SQL it runs. If you're scared of just letting it delete things and rather inspect the SQL before it runs, use:
现在这将删除您在模型中的列。-verbose说要向您展示它运行的 SQL。如果您害怕让它删除内容,而是在运行之前检查 SQL,请使用:
update-database -f -script
更新数据库 -f -script
That will instead dump the SQL out to a script you can look over, and run manually yourself.
这会将 SQL 转储到您可以查看的脚本中,然后自己手动运行。
In the case where you went on and deleted the column in the database manually, you now have a more complex scenario on your hands; the EdmMetadata table described in the other answer here contains a hash of the entire database that now does not match the database itself. You can run manual SQL to return the DB to the way Entity Framework expects (the way it was before you manually modified it, which brings it back in line with the hash) by inspecting what you had before and what your db currently looks like.
在您继续手动删除数据库中的列的情况下,您现在手头有一个更复杂的场景;此处另一个答案中描述的 EdmMetadata 表包含整个数据库的散列,该散列现在与数据库本身不匹配。您可以通过检查您之前拥有的内容以及您的数据库当前的样子,运行手动 SQL 以将 DB 返回到 Entity Framework 期望的方式(在您手动修改它之前的方式,这使其恢复与哈希一致)。
If that's not feasible you are now in the ugliest part of Entity Framework Code First. You need to eliminate the hash table and reverse engineer the db into code files.
如果这不可行,那么您现在处于 Entity Framework Code First 中最丑陋的部分。您需要消除哈希表并将数据库反向工程为代码文件。
The hash table name depends on the version of EF. In older EF4 like you were asking about, it's called EdmMetadata. In newer EF5, it's called __MigrationHistory (under System Tables in your database if you're looking in SQL Server Management Studio). You'll need to wipe it out.
哈希表名称取决于 EF 的版本。在您询问的较旧的 EF4 中,它称为 EdmMetadata。在较新的 EF5 中,它称为 __MigrationHistory(如果您在 SQL Server Management Studio 中查看,则在数据库中的系统表下)。你需要把它擦掉。
The good news on the second step, reverse engineering the db into code, is that Microsoft has released a tool into beta that will do this for you.
第二步的好消息是,将数据库逆向工程为代码,微软已经发布了一个测试版工具,可以为你做这件事。
Walk-through of reverse-engineering a db, and EF Power Tools
对 db 和 EF Power Tools 进行逆向工程演练
You can skip many of the first steps there since they're just setting up a DB and adding some nonsense to it so they can demonstrate what you need to do: Reverse Engineer a db.
您可以跳过其中的许多第一步,因为他们只是在设置数据库并向其添加一些废话,以便他们可以演示您需要做什么:对数据库进行逆向工程。
Update:
更新:
It can also be feasible to use a Manual Migration to work around this scenario. Make a backup of the db, then run:
使用手动迁移来解决这种情况也是可行的。备份数据库,然后运行:
add-migration WhateverYouWantToCallThis
The modifications to the db EF Migrations that need to be run will appear in the generated C# commands. Now it's up to you to tinker with them to both work around the problems with what it's attempting to do (for example attempting to delete columns that have already been deleted), and put into place things it will need going forward (for example adding back a table you still have in your model but you manually deleted in your db).
对需要运行的 db EF Migrations 的修改将出现在生成的 C# 命令中。现在由您来修补它们以解决它正在尝试执行的操作的问题(例如尝试删除已删除的列),并放置它需要前进的东西(例如添加回来您的模型中仍有一个表,但您在数据库中手动删除了该表)。
Once you've added this and run update-database -f, EF Code First will just accept on faith that you've updated the database the way it needs to be, and update its hash based on the end result. If you made the right changes you can now proceed with Migrations as normal. If this still causes errors you can usually copy the commands of the manual migration out somewhere and delete it, Restore the db from your backup, add a manual migration again and try again. Worst case you resort to the reverse engineering step above.
一旦你添加了这个并运行update-database -f,EF Code First 就会相信你已经按照它需要的方式更新了数据库,并根据最终结果更新它的哈希。如果您进行了正确的更改,您现在可以照常进行迁移。如果这仍然导致错误,您通常可以将手动迁移的命令复制到某处并将其删除,从备份中恢复数据库,再次添加手动迁移并重试。最坏的情况是您求助于上面的逆向工程步骤。
回答by Manatherin
take a look at
看一眼
Step 5: Changing our Model
第 5 步:更改我们的模型
回答by Ladislav Mrnka
If your database contains some strange table with name EdmMetadatayour context uses some very basic level of database versioning. When it created the database it stored a hash of your model into this table and each time it builds a model for your application (first time you use the context after restarting your application) it again computes the hash and compares it with the hash stored in that table. It means that any change in your model will result in a different hash and EF will react with the exception you see. Manual change in the database will not help you because the table contains still the old has.
如果您的数据库包含一些带有名称EdmMetadata的奇怪表,您的上下文将使用一些非常基本的数据库版本控制级别。当它创建数据库时,它将模型的散列存储到此表中,每次为应用程序构建模型时(重新启动应用程序后第一次使用上下文),它都会再次计算散列并将其与存储在其中的散列进行比较那张桌子。这意味着您的模型中的任何更改都将导致不同的哈希值,EF 将对您看到的异常做出反应。手动更改数据库对您没有帮助,因为表包含的仍然是旧的。
The solutions are:
解决方法是:
- Removing this versioning. It requires removing
IncludeMetadataConventionas described here. - Updating the hash. It would require to reverse engineer the algorithm for hash computation (for example by Red Gate .NET Reflector, JetBrains dotPeek, SharpDevelop ILSpy or Telerik JustDecompile) and computing new hash from compiled model (or using reflection to read internal property from
DbCompiledModel.ModelHashwith already computed hash) which you will store in theEdmMetadatatable. - Manually deleting the database and let EF create a new one - you will lose all data
- Setting initializer to
DropCreateDatabaseIfModelChanges- it will automatically delete the database and create a new one if you change the model - you will lose all data
- 删除此版本控制。它需要
IncludeMetadataConvention按照此处所述进行删除。 - 更新哈希。它需要对哈希计算算法进行逆向工程(例如通过 Red Gate .NET Reflector、JetBrains dotPeek、SharpDevelop ILSpy 或 Telerik JustDecompile)并从编译模型计算新哈希(或使用反射从
DbCompiledModel.ModelHash已计算的哈希中读取内部属性)) 您将存储在EdmMetadata表中。 - 手动删除数据库并让 EF 创建一个新数据库 - 您将丢失所有数据
- 将初始化程序设置为
DropCreateDatabaseIfModelChanges- 如果您更改模型,它将自动删除数据库并创建一个新数据库 - 您将丢失所有数据
回答by WWC
Check out this article's section on Code First Migrations with an Existing Database
http://msdn.microsoft.com/en-us/data/dn579398
查看本文关于使用现有数据库进行代码优先迁移的部分
http://msdn.microsoft.com/en-us/data/dn579398
Sometimes your project and your database may get out of synch. So you may have to resynch your schema based off your existing database.
有时您的项目和您的数据库可能会不同步。因此,您可能必须根据现有数据库重新同步架构。
1) To create a migration based off the existing schema:
Add-Migration InitialCreate
1) 基于现有架构创建迁移:
Add-Migration InitialCreate
2) Run Update-Database after that to add the entry into the _MigrationsHistory table to indicate that the migration is complete up to the existing schema.
2) 之后运行 Update-Database 将条目添加到 _MigrationsHistory 表中以指示迁移已完成到现有模式。
回答by Ali Adravi
Three simple things you need to remember when working on Code First
使用 Code First 时需要记住的三件事
- Enable-Migrations
- Add-Migration
- Update-Database
- 启用迁移
- 添加迁移
- 更新数据库
Everything is self explanatory.
一切都是不言自明的。
You need to run these commands on Package Manager Console manually. I am late but hope it will help
您需要在包管理器控制台上手动运行这些命令。我迟到了,但希望它会有所帮助

