欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何利用FluentMigrator实现数据库迁移

程序员文章站 2023-12-12 08:10:28
fluentmigrator fluent migrator是一个基于.net的迁移框架,你可以像使用ruby on rails migrations一样使用它。fl...

fluentmigrator

fluent migrator是一个基于.net的迁移框架,你可以像使用ruby on rails migrations一样使用它。fluent migrator的最新版本是3.13版,官网地址。 你可以使用c#编写数据库迁移类,而不需要编写任何sql脚本。从使用方式上看,它非常像ef/ef core的数据库迁移脚本,但是它支持的数据库类型比ef/ef core多的多,且不受限与ef/ef core。

支持的数据库列表

  • microsoft sql server 2017
  • microsoft sql server 2016
  • microsoft sql server 2014
  • microsoft sql server 2008
  • microsoft sql server 2005
  • microsoft sql server 2000
  • microsoft sql server compact edition
  • postgresql
  • mysql 4
  • mysql 5
  • oracle
  • oracle (managed ado.net)
  • oracle (dotconnect ado.net)
  • microsoft jet engine (access)
  • sqlite
  • firebird
  • amazon redshift
  • sap hana
  • sap sql anywhere
  • db2
  • db2 iseries

fluent migrator提供了5个不同的类库来支持不同的场景。

package 描述
fluentmigrator 创建数据库所需的基础程序集
fluentmigrator.runner 进程内执行数据库迁移所需的程序集
fluentmigrator.console 进程外执行数据库迁移所需的程序集,它兼容.net 4.0/4.5/.net core 2.0
fluentmigrator.msbuild 兼容.net 4.0/4.5/.net standard 2.0的msbuild任务
fluentmigrator.dotnet.cli 可执行数据库迁移的.net core cli工具

入门例子

这里我们首先演示一个最简单的数据库迁移例子,为一个mysql数据库添加一个日志表。

创建控制台程序

我们使用.net core cli创建一个.net core的命令行程序。

# 迁移脚本基础库
dotnet add package fluentmigrator

# 迁移脚本运行库
dotnet add package fluentmigrator.runner

# 针对mysql的迁移脚本支持库
dotnet add package fluentmigrator.runner.mysql

# ado.net针对mysql的驱动器
dotnet add package mysql.data

添加第一个数据库迁移类

未了创建一个名为log的表,这里需要创建一个数据库迁移类

  • log表中有2个字段,一个是id字段,一个是text字段
  • id字段是int64类型的主键,且自增
  • text字段是字符串字段
using fluentmigrator;

namespace test
{
 [migration(20180430121800)]
 public class addlogtable : migration
 {
  public override void up()
  {
   create.table("log")
    .withcolumn("id").asint64().primarykey().identity()
    .withcolumn("text").asstring();
  }

  public override void down()
  {
   delete.table("log");
  }
 }
}

运行迁移类

编写完迁移类之后,我们就可以开始运行迁移类了。

fluent migrator有两种运行迁移脚本的方式。

  • 使用进程内执行器(推荐)
  • 使用进程外执行器

使用进程内执行器

所谓的进行内执行器,其实就是借助fluentmigrator.runner库,在程序内部手动调用imigrationrunner接口对象的migrateup方法执行数据库迁移。

这里我们可以修改program.cs文件如下。

 class program
 {
  static void main(string[] args)
  {
   var serviceprovider = createservices();

   using (var scope = serviceprovider.createscope())
   {
    updatedatabase(scope.serviceprovider);
   }
  }

  private static iserviceprovider createservices()
  {
   return new servicecollection()
    //添加fluentmigrator基础服务
    .addfluentmigratorcore()
    .configurerunner(rb => rb
     //添加mysql 5.0支持
     .addmysql5()
     //配置连接字符串
     .withglobalconnectionstring("server=localhost;port=3307;database=abc;uid=root;pwd=123456")
     //检索迁移配置
     .scanin(typeof(addlogtable).assembly).for.migrations())
    //启用控制台日志
    .addlogging(lb => lb.addfluentmigratorconsole())
    //构建服务提供器
    .buildserviceprovider(false);
  }

  private static void updatedatabase(iserviceprovider serviceprovider)
  {
   //初始化进程内迁移构建器
   var runner = serviceprovider.getrequiredservice<imigrationrunner>();

   //执行迁移脚本
   runner.migrateup();
  }
 }

启动程序之后,迁移自动完成。

如何利用FluentMigrator实现数据库迁移 

使用进程外执行器

如果你想使用进行外迁移执行器,这里首先需要保证你已经安装了.net core 2.1或以上版本的sdk, 因为你需要使用.net core 2.1之后新增的global tool功能。

这里我们可以使用命令行,添加fluentmigrator.dotnet.cli这个工具

dotnet tool install -g fluentmigrator.dotnet.cli

安装完成之后,我们就可以使用这个工具来做数据库迁移了

dotnet fm migrate -p mysql -c "server=localhost;port=3307;database=abc;uid=root;pwd=123456" -a ".\bin\debug\netcoreapp2.1\test.dll"

这个方法有3个参数, 第一个参数-p指定了数据库的类型,第二个参数-c指定了连接字符串,第三个参数-a指定了包含迁移类的程序集路径。

注意:其实这里还有第四个参数command, 可选值为down/up, 如果不指定,默认是up, 即运行所有还未运行过的数据库迁移类。

方法执行后,效果和进程内执行器的效果一致。

基本概念

在展示了一个简单示例之后,我们接下来看一下fluent migrator中的一些基本概念。

迁移(migrations)

fluent migrator中最基础的元素是迁移类,每个迁移类都需要继承自一个名为migration的抽象类,并实现两个抽象方法up和down, 顾名思义up方法即执行当前的数据库变更,down方法即回滚当前的数据库变更。

[migration(1)]
public class createusertable : migration
{
 public override void up()
 {
  create.table("users");
 }

 public override void down()
 {
  delete.table("users");
 }
}

这里你可能注意到迁移类的头部,有一个migration的特性,它的值是1, 这里其实是指定了迁移类执行的顺序,编号越小的迁移类越先执行(有一部分开发人员系统会使用当前日期的yyyymmddhhmmss格式来标记迁移类),这个编号必须是唯一的,不能重复。

fluent接口(fluent interface)

fluent migrator提供非常丰富的fluent api, 我们可以使用这些api来创建表,列,索引。 基本上你能用到的大部分场景它都支持。

创建表达式(create expression)

你可以使用它创建表达式来添加表,列,索引,外键,组织结构(schema)

create.table("users")
  .withidcolumn() 
  .withcolumn("name").asstring().notnullable();

注:withidcolumn()是一个扩展方法,它等价于.withcolumn("id").asint32().notnullable().primarykey().identity();

create.foreignkey() 
  .fromtable("users").foreigncolumn("companyid")
  .totable("company").primarycolumn("id");

变更表达式(alter expression)

用来变更已存在的表和列

alter.table("bar")
  .addcolumn("somedate")
  .asdatetime()
  .nullable();
alter.table("bar")
  .altercolumn("somedate")
  .asdatetime()
  .notnullable();
alter.column("somedate")
  .ontable("bar")
  .asdatetime()
  .notnullable();

删除表达式(delete expression)

用来删除表,列,外键,组织结构(schema)

delete.table("users");

删除多个列(delete multiple columns)

fluent migrator也提供了一个删除多列的语法

delete.column("allowsubscription").column("subscriptiondate").fromtable("users");

执行脚本(execute expression)

允许你执行自定义的sql脚本或执行指定的sql脚本文件

execute.script("myscript.sql");
execute.embeddedscript("updatelegacysp.sql");
execute.sql("delete table users");

这里embeddedscript方法也是执行指定的sql脚本文件,但是它的文件来源embbed resource中读取。如果你想使用embbedscript只需要将指定的sql脚本文件的build action属性设置为embbed resource即可。

重命名表达式(rename expression)

允许重命名表或列

rename.table("users").to("usersnew");
rename.column("lastname").ontable("users").to("surname");

数据操作表达式(data expressions)

允许对数据库数据进行新增/修改/删除操作

insert.intotable("users").row(new { firstname = "john", lastname = "smith" });
delete.fromtable("users").allrows(); //删除所有行
delete.fromtable("users").row(new { firstname = "john" }); //删除所有firstname = john的数据行
delete.fromtable("users").isnull("username"); //删除所有username为空的数据行
update.table("users").set(new { name = "john" }).where(new { name = "johnanna" });

数据库类型判断表达式(ifdatabase expression)

允许根据数据库类型,执行不同的数据库迁移操作

ifdatabase("sqlserver", "postgres")
  .create.table("users")
  .withidcolumn()
  .withcolumn("name").asstring().notnullable();

ifdatabase("sqlite")
  .create.table("users")
  .withcolumn("id").asint16().primarykey()
  .withcolumn("name").asstring().notnullable();

组织结构存在表达式(schema.exists expressions)

用来判断组织结构是否已经存在,列如判断表是否存在,列是否存在等等。

if (!schema.table("users").column("firstname").exists())
{
  this.create.column("firstname").ontable("users").asansistring(128).nullable();
}

配置(profile)

fluent migrator还提供了一个profile的特性,使用该配置,开发人员可以对针对的不同的环境(开发环境,测试环境,生产环境等)运行不同的脚本。

[profile("development")]
public class createdevseeddata : migration
{
  public override void up()
  {
    insert.intotable( "user" ).row( new
      {
        username = "devuser1",
        displayname = "dev user"
      });
  }

  public override void down()
  {
    //empty, not using
  }
}

和ef/ef core的脚本迁移比较

fluent migrator的数据库脚本迁移与ef/ef core非常类似。

相似点:

  • 当我们使用ef/ef core做数据库迁移的时候,会在当前数据库中创建一个__efmigrationshistory表,并在其中保存运行过的脚本id。
  • 当我们使用fluent migrator做数据库迁移的时候,也会在数据库中创建一个versioninfo表,并在其中保存运行过的脚本id

区别:

  • ef/ef core的迁移脚本是根据ef上下文配置以及最新的modelsnapshot自动生成的,更方便一些。fluent migrator的迁移脚本,都需要自己手动编写, 更灵活一些。
  • ef/ef core每次自动生成的迁移文件一个cs文件一个design.cs文件,每个cs文件中包含了自动生成的脚本类,design.cs里面包含了针对当前迁移类的最新modelsnapshot, 所以重度使用ef/ef core, 最后累计生成的design.cs文件都会非常大。fluent migrator的每个迁移类都是自己编写的,只包含本次迁移的内容,所以体积更小。

总结

本篇中我描述了fluent migrator的一些基本用法,以及它与ef/ef core脚本迁移的区别, 如果你不是重度ef/ef core的使用者,可以尝试一下使用fluent migrator来做数据库迁移。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。

上一篇:

下一篇: