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

时间:2011-07-08 00:09:43

标签: .net c#-4.0 entity-framework-4.1 ef-code-first sql-server-ce

我构建了一个小型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; }
}

...它抛出了这个异常:

  

自创建数据库以来,支持'NerdDinners'上下文的模型已更改。手动删除/更新数据库,或使用IDatabaseInitializer实例调用Database.SetInitializer。例如,DropCreateDatabaseIfModelChanges策略将自动删除并重新创建数据库,并可选择使用新数据对其进行播种。

即使从数据库中手动删除字段“HosteBy”,错误仍然存​​在。我在这里错过了什么?我是否必须删除/截断数据库,还是有其他解决方案?

5 个答案:

答案 0 :(得分:25)

在您更改Code First Model的第一个场景中,在您手动修改数据库之前,答案是打开(Nuget)Package Manager控制台并键入:

update-database -verbose

除了 - 因为在这种情况下你要移除一个列,这将报告它将要删除的东西,并且如果没有明确说明没有,它将不会删除任何内容。所以你输入:

update-database -f -verbose

现在,这将删除模型中的列。 -verbose说要向您展示它运行的SQL。如果你害怕只是让它删除东西而不是在运行之前检查SQL,请使用:

update-database -f -script

而是将SQL转储到您可以查看的脚本,然后自己手动运行。

如果你继续手动删除了数据库中的列,那么现在你手上有一个更复杂的场景;此处另一个答案中描述的EdmMetadata表包含整个数据库的哈希,现在与数据库本身不匹配。您可以运行手动SQL,以便按照Entity Framework预期的方式(通过手动修改它之前的方式,使其与哈希一致)恢复数据库,方法是检查之前的内容以及数据库当前的状态。

如果这不可行,您现在处于Entity Framework Code First中最丑陋的部分。您需要消除哈希表并将数据库反向工程为代码文件。

哈希表名称取决于EF的版本。在你想问的旧版EF4中,它被称为EdmMetadata。在较新的EF5中,它被称为__MigrationHistory(如果您正在查看SQL Server Management Studio,则在数据库的系统表下)。你需要把它擦掉。

第二步的好消息是将数据库反向设计为代码,微软已经发布了一个测试工具,可以为你做这个。

Walk-through of reverse-engineering a db, and EF Power Tools

你可以跳过那里的许多第一步,因为他们只是设置一个数据库并为它添加一些废话,以便他们可以演示你需要做什么:逆向工程数据库。

更新

使用手动迁移来解决此问题也是可行的。备份数据库,然后运行:

add-migration WhateverYouWantToCallThis

需要运行的db EF Migrations的修改将出现在生成的C#命令中。现在由你来修补它们以解决它试图做的事情(例如试图删除已经删除的列),并实现它将需要的东西(例如添加回来)您在模型中仍然拥有的表,但您在数据库中手动删除了该表。

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

答案 1 :(得分:3)

答案 2 :(得分:2)

如果您的数据库包含一些名为EdmMetadata的奇怪表,则您的上下文使用一些非常基本的数据库版本控制级别。当它创建数据库时,它会将模型的哈希存储到此表中,并且每次为应用程序构建模型时(第一次在重新启动应用程序后使用上下文)它再次计算哈希并将其与存储在中的哈希进行比较。那张桌子。这意味着模型中的任何更改都将导致不同的哈希值,EF将对您看到的异常做出反应。手动更改数据库对您没有帮助,因为该表还包含旧的。

解决方案是:

  • 删除此版本控制。它需要删除here所述的IncludeMetadataConvention
  • 更新哈希。它需要对哈希计算的算法进行逆向工程(例如,通过Red Gate .NET Reflector,JetBrains dotPeek,SharpDevelop ILSpy或Telerik JustDecompile)并从编译模型中计算新哈希(或使用反射从{{1}读取内部属性已经计算好的哈希),你将存储在DbCompiledModel.ModelHash表中。
  • 手动删除数据库并让EF创建一个新数据库 - 您将丢失所有数据
  • 将初始化程序设置为EdmMetadata - 如果更改模型,它将自动删除数据库并创建一个新数据库 - 您将丢失所有数据

答案 3 :(得分:0)

查看本文的“使用现有数据库进行代码优先迁移”一节 http://msdn.microsoft.com/en-us/data/dn579398

有时您的项目和数据库可能会失去同步。   因此,您可能必须根据现有数据库重新同步模式。



1)基于现有模式创建迁移:
添加迁移InitialCreate

2)之后运行Update-Database将条目添加到_MigrationsHistory表中,以指示迁移已完成,直到现有模式。

答案 4 :(得分:0)

在使用Code First时需要记住三件简单的事情

  1. 启用 - 迁移
  2. 添加-迁移
  3. 更新的数据库的
  4. 一切都是自我解释的。

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