标题: 如何使用 FluentMigrator 进行数据库迁移
地址: https://www.cnblogs.com/lwqlun/p/10649949.html
作者: Lamond Lu
FluentMigrator
Fluent Migrator 是一个基于. NET 的迁移框架, 你可以像使用 Ruby on Rails Migrations 一样使用它. Fluent Migrator 的最新版本是 3.13 版, 官网地址 https://github.com/fluentmigrator/fluentmigrator . 你可以使用 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 new console
添加程序集
接下来, 我们需要添加必要的程序集.
- # 迁移脚本基础库
- 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();
- }
- }
启动程序之后, 迁移自动完成.
使用进程外执行器
如果你想使用进行外迁移执行器, 这里首先需要保证你已经安装了. 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 来做数据库迁移.
来源: https://www.cnblogs.com/lwqlun/p/10649949.html