Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在模型更改时更新数据库架构而不丢失数据_C#_Entity Framework_Ef Code First_Database Update - Fatal编程技术网

C# 在模型更改时更新数据库架构而不丢失数据

C# 在模型更改时更新数据库架构而不丢失数据,c#,entity-framework,ef-code-first,database-update,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 ri

背景:假设我正在使用实体框架,其中一个映射的实体如下所示:

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
表仍将有一个名为
ID
的列,它将抛出一个异常,告诉我该列
FooID
不存在

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

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


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

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

说明:如果您的团队刚加入EF时与我们一样,您将无法创建新的本地数据库,或者无法对生产数据库应用更新。你想回到一个干净的EF环境,然后坚持基本原则,但你不能。如果让它用于生产,则无法创建本地数据库,如果让它用于本地,则生产服务器将失去同步。最后,您不想删除任何生产服务器数据

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

错误消息:System.Data.SqlClient.SqlException(0x80131904):没有 已是数据库中名为“”的对象

问题背景:EF根据数据库中名为dbo的表了解当前数据库的位置与代码的位置。当它查看迁移脚本时,它会尝试用脚本重新确定最后的位置。如果不能,它只会尝试按顺序应用它们。这意味着,它返回到初始创建脚本,如果您查看UP命令的第一部分,它将是发生错误的表的createTable

为了更详细地理解这一点,我建议观看此处引用的两个视频:

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

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

步骤2:本地环境清洁 打开“迁移”文件夹并将其删除。我想如果必要的话,你可以从git那里得到这些

步骤3:重新创建初始值 在包管理器中,运行“启用迁移”(如果有多个上下文,EF将提示您使用-ContextTypeName)。 运行“添加迁移初始-详细”。这将创建初始脚本,以基于当前代码从头开始创建数据库。 如果您在先前的Configuration.cs中有任何种子操作,请将其复制到其他位置

步骤4:技巧EF 此时,如果我们运行更新数据库,我们将得到原始错误。因此,我们需要诱使EF认为它是最新的,而不运行这些命令。因此,在您刚刚创建的初始迁移中使用Up方法,并将其全部注释掉

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

步骤6:确认EF实际上是最新的 如果您有尚未应用迁移的代码,这就是我所做的

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

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

步骤7:重新确认并提交。 构建、测试、运行。确保所有内容都在运行,然后提交更改

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

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);
}