更新模型更改时的数据库架构,不会丢失数据

时间:2012-02-22 05:34:29

标签: c# entity-framework ef-code-first database-update

背景:假设我正在使用实体框架,其中一个实体映射为:

class Foo
{
    public int ID { get; set; }
    public string Bar { get; set; }
    // other useful properties
}

使用映射:

class FooMap : EntityTypeConfiguration<Foo>
{
    // bear me with, I know this is redundant right now
    ToTable("Foo");
    HasKey(e => e.ID);
    Property(e => e.ID).HasColumnName("ID");
    Property(e => e.Bar);
}

在某个地方,我们需要更改Foo的列名称,因为我的老板告诉我Foo需要比ID更奢侈的名称,否则我们的客户将是不高兴。他告诉我们将它重命名为“FooID”:

class FooMap : EntityTypeConfiguration<Foo>
{
    // bear me with, I know this is redundant right now
    ToTable("Foo");
    HasKey(e => e.ID);
    Property(e => e.ID).HasColumnName("FooID"); // Now you map to FooID
    Property(e => e.Bar);
}

就目前而言,如果我这样做,一切都不会改变。 Foo表仍然会有一个名为ID的列,它会抛出一个异常,告诉我列FooID不存在。

问题:如何让实体框架认识到我现在希望更新Foo表,以便名为ID的列现在命名为{{ 1}}?

更一般地说,如何让实体框架自动将我的代码中的更改传播到实际的数据库中(例如在应用程序启动时)而不会破坏现有数据?

我不能只是“删除并重新创建”数据库,因为超出此问题范围的原因,数据库会在其中存储一些其他数据,这些数据不是通过我的代码中映射的模型创建的。删除它会导致我们丢失我们无法使用此机制重新创建的表。

3 个答案:

答案 0 :(得分:4)

答案 1 :(得分:2)

如何从Entity Framework中恢复噩梦 - 数据库已经有了同名的表

说明:如果您的团队不熟悉我们,那么您就会喜欢我们,您最终会处于无法创建新本地的状态数据库或您无法将更新应用于生产数据库。你想回到一个干净的EF环境,然后坚持基础,但你不能。如果您将其用于生产,则无法创建本地数据库,如果您将其用于本地数据库,则生产服务器将不同步。最后,您不想删除任何生产服务器数据。

症状:无法运行 更新数据库 ,因为它正在尝试运行创建脚本和数据库已经有了同名的表。

  

错误消息:System.Data.SqlClient.SqlException(0x80131904):有   已经是一个名为&#39;&#39;在数据库中。

问题背景:EF根据数据库中名为dbo .__ MigrationHistory的表,了解当前数据库所处位置与代码所在位置的对比情况。当它查看Migration Scripts时,它会尝试使用脚本重新构建它的最后位置。如果它不能,它只是尝试按顺序应用它们。这意味着,它将返回到初始创建脚本,如果您查看UP命令的第一部分,它将成为发生错误的表的CreeateTable。

为了更详细地了解这一点,我建议您观看此处引用的两个视频: https://msdn.microsoft.com/en-us/library/dn481501(v=vs.113).aspx

解决方案:我们需要做的是让EF认为当前数据库是最新的,而不是应用这些CreateTable命令。与此同时,我们仍然希望这些命令存在,以便我们可以创建新的本地数据库。

第1步:生产数据库清理 首先,备份生产数据库。在SSMS中,右键单击数据库,选择&#34;任务&gt;导出数据层应用程序......&#34;并按照提示操作。 打开生产数据库并删除/删除dbo .__ MigrationHistory表。

第2步:本地环境清洁 打开迁移文件夹并将其删除。我假设如果有必要,你可以从git中取回所有这些。

第3步:重新创建初始 在程序包管理器中,运行&#34;启用 - 迁移&#34; (如果您有多个上下文,EF将提示您使用-Co​​ntextTypeName)。 运行&#34; Add-Migration Initial -verbose&#34;。这将创建初始脚本,以便根据当前代码从头开始创建数据库。 如果您在之前的Configuration.cs中有任何种子操作,则将其复制到。

第4步:欺骗EF 此时,如果我们运行 更新数据库 ,我们就会收到原始错误。因此,我们需要让EF认为它是最新的,而不需要运行这些命令。因此,在刚刚创建的初始迁移中进入Up方法并将其全部注释掉。

第5步:更新数据库 如果没有代码在Up进程上执行,EF将使用正确的条目创建dbo .__ MigrationHistory表,以表明它正确运行了此脚本。如果你愿意,去看看吧。 现在,取消注释该代码并保存。 如果要检查EF是否认为其是最新的,则可以再次运行 更新数据库 。它不会使用所有CreateTable命令运行Up步骤,因为它认为它已经完成了。

第6步:确认EF实际上是最新的 如果你的代码还没有应用迁移,那就是我做的......

运行&#34;添加迁移MissingMigrations&#34; 这实际上会创建一个空脚本。因为代码已经存在,所以在初始迁移脚本中实际上有正确的命令来创建这些表,因此我只是将CreateTable和等效的drop命令切换为Up和Down方法。

现在,再次运行 Update-Database 并观察它执行新的迁移脚本,在数据库中创建相应的表。

第7步:重新确认并提交。 构建,测试,运行。确保一切正在运行,然后提交更改。

第8步:让团队的其他成员知道如何继续。 当下一个人更新时,EF不知道是什么击中它,因为它已经运行的脚本不存在之前。但是,假设本地数据库可以被吹走并重新创建,这一切都很好。他们需要删除他们的本地数据库并再次添加从EF创建它。如果他们有本地更改和待定迁移,我建议他们再次在master上创建他们的数据库,切换到他们的功能分支并从头开始重新创建这些迁移脚本。

答案 2 :(得分:1)

您必须使用Entity Framework迁移才能执行此操作

use this link