2012-02-22 105 views
3

背景:比方说,我使用的是实体框架和映射的一个实体给出如下:更新数据库架构

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列现在被命名为FooID

更一般地说,我怎样才能让实体框架自动将我的代码中的更改传播到实际的数据库中(比如在应用程序启动时)而不销毁现有数据?

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

回答

1

如何从实体框架的噩梦中恢复 - 数据库已经有同名

说明表:如果你像我们一样,当你的球队对于EF来说是新手,最终会处于无法创建新本地数据库或者无法将更新应用于生产数据库的状态。你想回到一个干净的EF环境,然后坚持基本的,但你不能。如果你的产品可以用于生产,你不能创建一个本地数据库,并且如果你的本地数据库适用于本地数据库,那么你的生产服务器就会失去同步。最后,您不想删除任何生产服务器数据。

症状:因为它试图运行创建脚本和数据库已经与名称相同的表不能运行更新,数据库

错误消息信息:System.Data.SqlClient.SqlException(0x80131904):有 是已经在数据库中名为 '' 的对象。

问题背景:EF理解,其中当前数据库是与其中的代码是在基于数据库中的称为DBO .__ MigrationHistory的表在。当它查看迁移脚本时,它会尝试重新定位脚本的最后位置。如果它不能,它只是试图按顺序应用它们。这意味着它返回到初始创建脚本,并且如果您查看UP命令的第一部分,它将成为发生错误的表的CreeateTable。

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

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

第1步:生产DB清洁 首先,备份你的生产数据库。在SSMS中,右键单击数据库,选择“任务>导出数据层应用程序...”并按照提示进行操作。 打开您的生产数据库并删除/删除dbo .__ MigrationHistory表。

第2步:本地环境的清洁 打开迁移的文件夹并将其删除。我假设你可以根据需要从git中得到这一切。

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

第4步:天雷EF 在这一点上,如果我们跑更新,数据库,我们会越来越原来的错误。所以,我们需要让EF认为它是最新的,而不需要运行这些命令。因此,请在刚刚创建的初始迁移中进入Up方法,并将其全部注释掉。

第5步:更新数据库内 由于没有代码的过程中执行,EF将创建正确的入口说它正确运行此脚本DBO .__ MigrationHistory表。去看看,如果你喜欢。 现在,取消注释该代码并保存。 如果你想检查EF认为它是否是最新的,你可以运行更新数据库。它不会用所有的CreateTable命令运行Up步骤,因为它认为它已经完成了。

第6步:确认EF实际上是最新的 如果你有这样的尚未有适用于它迁移代码,这是我做的......

运行“添加 - 迁移MissingMigrations “ 这实际上会创建一个空脚本。由于代码已经存在,实际上在初始迁移脚本中有正确的命令来创建这些表,因此我只是将CreateTable和等效的放置命令切入Up和Down方法中。

现在,运行更新,数据库再次,看它执行新的迁移脚本,在数据库中创建适当的表。

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

第8步:让其余的团队知道如何继续。 当下一个人更新时,由于它之前运行的脚本不存在,EF将不知道该命中了什么。但是,假设本地数据库可以被删除并重新创建,这是很好的。他们将需要删除他们的本地数据库,并添加从EF重新创建它。如果他们有本地更改和未决迁移,我建议他们在主服务器上再次创建他们的数据库,切换到他们的功能分支并从头开始重新创建这些迁移脚本。