Entity Framework 迁移的使用场景

EF拥有迁移功能,虽然很强大,但还是需要明白这一个功能的目的和使用场景。一般情况下,当你是用Code First时,Migrations就很有必要了。例如,你在生产环境中,经常更新Poco对象,而初始化器使用的是DropCreateDatabaseAlways或者DropCreateDatabaseIfModelChanges,那么你的数据库中总是处于初始化状态,如果想保留一部分数据,很遗憾,当部署到产品环境中时数据将会丢失。我们希望即使在产品环境下,以前保存的数据不会被丢失。简单地说:

当你在开发应用程序时,你会对数据模型进行频繁的更改,随着每一次的更改,数据模型与数据库架构将不再一致。你已经对Entity Framework进行了配置让其在每一次数据模型更改时自动的删除并重新创建数据库。当你添加、删除或更改实体类或更改DbContext类后重新运行应用程序,它会自动的删除已存在的数据库并创建一个和当前数据模型相匹配的数据库,最后使用测试数据初始化。

在你将应用程序部署到生产环境之前,这种方法会一直保持数据模型和数据库架构的一致性。当应用程序运行在生产环境并已经存储了一部分数据时,你不想在数据模型变更(例如添加一个列)时丢掉这部分数据,Code First迁移功能能够通过更新数据库架构而不是删除并重建数据库来很好的解决这个问题。 

我们的目标之一:一旦使用初始化器产生了数据库结构,那么从现在开始,希望能基于已有的基架修修补补,而不希望推倒重来,并且希望已经添加到数据库中的数据不要丢失。【使用DropCreateDatabaseIfModelChanges等初始化器时,如果改变了Poco对象的属性或关系映射,将会导致数据库重建。要命的是,总是会报数据库正在使用的错误,除非你手动地删除已经创建的数据库。虽然你能通过在初始化器中Seed方法中播种数据,但操作很繁琐,不利于部署和回滚。】

我们的目标之二:生产环境的程序测试通过后,能够一键部署到产品环境的服务器上,并且保留测试环境下的部分数据。

试想以下一个生产场景:

  • 新建了一个DbContext名叫MyDbContext不指明初始化器时,会默认使用CreateDatabaseIfNotExists。
  • 第一次使用new MyDbcontxt对象,并访问其中的数据集DbSet。会导致数据库的创建。
  • 现在你修改了数据集模型的结构,如给Blog多添加了一个叫Summary的属性。
  • 再次运行程序,new MyDbContext,则会报出异常:MyContext上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库。

如何解决?

第一种方法:如前一篇博客所写,创建一个全局的MyDbContext,专门使用DropCreateDatabaseIfModelChanges,让它删除数据库,重新创建。

第二种方法:也就是今天的主题,使用迁移来完成。异常产生的原因是:Poco对象的ModelMeta与数据库中保存的不一致。迁移的本质就是让VS根据Code First的ModelMeta与数据库中保存的ModelMeta进行对比猜测,自动生成一份向前和回滚的代码,具体过程应该这样操作:

  1. 在程序包管理器控制台中运行 Enable-Migrations 命令:enable-migrations。此命令已为项目添加了 Migrations 文件夹,此新文件夹包含两个文件:Configuration.cs 和<timestamp>_InitialCreate.cs文件。后者只有在已经创建数据库结构的前提下产生,因为它是根据数据库保存的Model Meta创建的基架。如果还没有数据库结构,则后者将不会存在,除非首次调用 Add-Migration 时,会根据Poco对象的Model Meta创建第一份基架。
  2. 然后,我们知道Poco对象由于为Blog对象添加了一个Summary属性而改变,此时在程序包管理器控制台中运行 Add-Migration AddBlogSummary 命令。 则在 Migrations 文件夹中,现在有了新的 AddBlogSummary 迁移。该迁移文件名以时间戳作为前缀,这对于排序十分有帮助。
  3. 在程序包管理器控制台中运行 Update-Database -Verbose -Script  命令。Code First 迁移将对 Migrations 文件夹中的迁移与已应用于数据库的迁移进行比较。它将了解到需要应用 AddBlogSummary 迁移,于是便运行该迁移。此时迁移将对 数据库进行更新,其 Blogs 表中包含了 Summary列。指令-Verbose是指明在窗口中输出执行脚本。指令-Script则会按照要求生成sql脚本。

上面的操作过程就完成了一次Poco对象模型的修改,并且数据库中的种子数据也不会丢失。实际上可以使用Update-Database -Script -SourceMigration: $InitialDatabase -TargetMigration: AddBlogSummary , 指定为其生成脚本的源和目标迁移。我们希望脚本用于从空数据库 ($InitialDatabase) 最新版本(迁移 AddBlogSummary )的迁移。如果指定目标迁移,迁移将使用最新迁移作为目标。如果未指定源迁移,迁移将使用数据库的当前状态。【注意迁移管道的概念。把每次迁移看成一个管道,可以自由回滚和向前。】

最后万事俱备,就等我们把这些代码部署到服务器运行了。此时,修改一下你的数据库链接,并且在使用MyDbContext之前,配置一下初始化器:

1 Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>());

然后,运行你的程序,初始化器自动使用迁移,将创建新的数据库并保留了数据,这正是我们想要的。

原文地址:https://www.cnblogs.com/khjian/p/5329097.html