实体框架代码优先:如何手动更新数据库?

时间:2022-01-19 02:19:39

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”字段后,该错误仍然存​​在。我在这里想念的是什么?我是否必须删除/截断数据库或是否有其他解决方案?

5 个解决方案

#1


25  

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 Model的第一个场景中,在您手动修改数据库之前,答案是打开(Nuget)Package Manager控制台并键入:

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. -verbose says 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

update-database -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,以便按照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中最丑陋的部分。您需要消除哈希表并将db反向工程为代码文件。

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

对数据库和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就会相信你已经按照它需要的方式更新数据库,并根据最终结果更新它的哈希值。如果您做了正确的更改,现在可以正常进行迁移。如果这仍然导致错误,您通常可以将手动迁移的命令复制到某处并将其删除,从备份中恢复数据库,再次添加手动迁移,然后重试。最糟糕的情况是你采取上面的逆向工程步骤。

#2


3  

take a look at

看一眼

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

Step 5: Changing our Model

第5步:更改我们的模型

#3


2  

If your database contains some strange table with name EdmMetadata your 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 IncludeMetadataConvention as described here.
  • 删除此版本控制。它需要删除此处所述的IncludeMetadataConvention。
  • 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.ModelHash with already computed hash) which you will store in the EdmMetadata table.
  • 更新哈希。它需要对用于哈希计算的算法进行反向工程(例如,通过Red Gate .NET Reflector,JetBrains dotPeek,SharpDevelop ILSpy或Telerik JustDecompile)并从编译模型计算新哈希(或使用反射从DbCompiledModel.ModelHash读取内部属性已经计算好的哈希值,你将存储在EdmMetadata表中。
  • Manually deleting the database and let EF create a new one - you will lose all data
  • 手动删除数据库并让EF创建一个新数据库 - 您将丢失所有数据
  • 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
  • 将初始化程序设置为DropCreateDatabaseIfModelChanges - 如果更改模型,它将自动删除数据库并创建一个新数据库 - 您将丢失所有数据

#4


0  

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表中,以指示迁移已完成,直到现有模式。

#5


0  

Three simple things you need to remember when working on Code First

在Code First上工作时需要记住三件简单的事情

  1. Enable-Migrations
  2. 启用的迁移
  3. Add-Migration
  4. 添加迁移
  5. Update-Database
  6. 更新数据库

Everything is self explanatory.

一切都是自我解释的。

You need to run these commands on Package Manager Console manually. I am late but hope it will help

您需要手动在Package Manager控制台上运行这些命令。我迟到了,但希望它会有所帮助

#1


25  

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 Model的第一个场景中,在您手动修改数据库之前,答案是打开(Nuget)Package Manager控制台并键入:

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. -verbose says 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

update-database -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,以便按照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中最丑陋的部分。您需要消除哈希表并将db反向工程为代码文件。

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

对数据库和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就会相信你已经按照它需要的方式更新数据库,并根据最终结果更新它的哈希值。如果您做了正确的更改,现在可以正常进行迁移。如果这仍然导致错误,您通常可以将手动迁移的命令复制到某处并将其删除,从备份中恢复数据库,再次添加手动迁移,然后重试。最糟糕的情况是你采取上面的逆向工程步骤。

#2


3  

take a look at

看一眼

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

Step 5: Changing our Model

第5步:更改我们的模型

#3


2  

If your database contains some strange table with name EdmMetadata your 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 IncludeMetadataConvention as described here.
  • 删除此版本控制。它需要删除此处所述的IncludeMetadataConvention。
  • 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.ModelHash with already computed hash) which you will store in the EdmMetadata table.
  • 更新哈希。它需要对用于哈希计算的算法进行反向工程(例如,通过Red Gate .NET Reflector,JetBrains dotPeek,SharpDevelop ILSpy或Telerik JustDecompile)并从编译模型计算新哈希(或使用反射从DbCompiledModel.ModelHash读取内部属性已经计算好的哈希值,你将存储在EdmMetadata表中。
  • Manually deleting the database and let EF create a new one - you will lose all data
  • 手动删除数据库并让EF创建一个新数据库 - 您将丢失所有数据
  • 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
  • 将初始化程序设置为DropCreateDatabaseIfModelChanges - 如果更改模型,它将自动删除数据库并创建一个新数据库 - 您将丢失所有数据

#4


0  

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表中,以指示迁移已完成,直到现有模式。

#5


0  

Three simple things you need to remember when working on Code First

在Code First上工作时需要记住三件简单的事情

  1. Enable-Migrations
  2. 启用的迁移
  3. Add-Migration
  4. 添加迁移
  5. Update-Database
  6. 更新数据库

Everything is self explanatory.

一切都是自我解释的。

You need to run these commands on Package Manager Console manually. I am late but hope it will help

您需要手动在Package Manager控制台上运行这些命令。我迟到了,但希望它会有所帮助