注:本文面向的是已经对EF的迁移功能有所了解,知道如何在控制台下进行相关命令输入的读者
问题
最近公司项目架构使用ABP进行整改,顺带想用EF的自动迁移代替了以前的手工脚本。
为什么要替代?
请看下图:
大版本就不用说了,每个小版本的发布我们都要准备一堆数据库升级脚本,这简直就是恶梦。
而使用ef它会自动帮我们完成数据库迁移,而我们只需要维护好迁移脚本就行了。
由于我们是线下项目,并且还有很多客户在使用老版本,所以我们不得不考虑既存表的问题。
而针对已存在的数据库,我们进行迁移时,总会出现Table_XXX已存在的问题,
这个很容易理解,因为就算是已存在的数据库
只要没有__migrationhistory表,它都会认为是一个新库而执行创建脚本。
第二个问题是公司需要对某些功能模块进行单独迭代和发布,说简单点就是以插件包的方式安装某些功能。
用过Orchard的朋友肯定知道它的模块化机制能够单独创建和维护属于自己部分的表,
没错,我们现在就是要实现类似的功能。
解决方案
1,对已存在的数据库的迁移
对待已存在的数据库的升级该怎么办?
其实很简单,选择当前的最新的一个发布版本作为一个EF迁移初始版本,所有到初始版本的数据库升级或则全新安装都使用DDL脚本进行。
选择好最新的发布版本后,我们使用
Add-Migration Initial
来创建一个初始化迁移脚本。
然后删除Up和Down方法体中的所有内容,如下:
然后就可以开始当前迭代的开发了,在DbContext修改完毕后,我们可以使用
Add-Migration XXXXXX_X.X.X(能够描述当前版本的名字)
来创建一个当前开发版本的迁移脚本,如下。
接下来要做的就是在初始化程序时让程序自动升级,
我所知道的能做这件事办法有:
1,通过官网发布的migrate.exe来执行迁移命令。
2,通过编程控制迁移。
3,通过nuget控制台执行Update-Database。
作为一个线下项目,第三种办法显然没法使用了,而第一种需要带上exe还要写些脚本,麻烦。
第二种办法有两个类可以实现:
1,DbMigrator
var dbMigrator = new System.Data.Entity.Migrations.DbMigrator(new Migrations.Configuration()); dbMigrator.Update();
2,MigrateDatabaseToLatestVersion
new MigrateDatabaseToLatestVersion<CoreServiceDbContext, Configuration>().InitializeDatabase(new CoreServiceDbContext());
不同之处是,前者可以选择更新的版本,后者如其名,在没有特别需求的情况下,任选其一即可。
上面的代码放在程序初始化的时候做就可以了,使用了ABP框架的朋友可以放在Data模块的PreInitialize做这件事。
或者放在global的application_start事件也不错。
这样就解决了对已存在的数据库进行自动升级的问题。
2,模块化数据迁移。
这个问题其实很好解决,每个模块配置自己的EF迁移设置时使用不同的ContextKey即可,如下:
(这是主业务功能的迁移设置)
(某模块的)
整体安装之后的迁移表如下:
可以看出各个模块都有不同的ContextKey且迁移记录都互不影响。
唯一有点遗憾是,由于我们使用Mysql并不支持DDL的事务管理,导致我们不得不在安装时手动拷贝整个数据库来以实现备份。
如果在SQLServer的环境下使用迁移的话,EF是会自动开启事务的,Oracle不太了解,有验证过的朋友麻烦留言告诉一声。