Fluent Migrator 是一個 .Net 的資料庫遷移 (Migration) 框架套件,其他如 Laravel 及 Ruby on Rails 也有類似的套件。遷移就像是資料庫的版本控制一樣,提供 Code-First 的方式去管理資料庫結構,並可將其納入專案的版控中。
官網:https://fluentmigrator.github.io/
一個建立 Users Table 的 Migration 範例:
[Migration(1)]
public class CreateUserTable : Migration
{
public override void Up()
{
Create.Table("Users")
.WithColumn("Id").AsInt32().PrimaryKey().Identity()
.WithColumn("Name").AsString(255);
}
public override void Down()
{
Delete.Table("Users");
}
}
可能會有人想說「為什麼不直接用 Entity framework 就好?」,EF 提供完整的 ORM,而這個套件只提供「遷移」這部分,算是另一種選擇,如果有專案因為效能問題不想使用 EF 但又想要有類似機制,就可以使用這個套件。
| 使用 Migration 框架 | 使用 SQL | |
|---|---|---|
| 支援不同的資料庫 | 套件有支援的都可以使用,寫一份就可以通用,且較不易出錯 | 要為每個資料庫個別去寫 SQL,需寫很多份,還要一個個去驗證執行是否正確 |
| 自動化執行 | 支援與 App 一同執行或使用 CLI 的方式 | 需自己處理 |
| 執行順序 | 可自訂每個 Migration 的版本,會照版本依序執行 | 無 |
| 紀錄 | 執行的紀錄將紀錄在 DB 某個 Table 中 | 無 |
| Rollback | 可 Rollback 到任意版本 | 需自己另外寫一份 SQL |
這個套件有把執行跟寫分開,依照自己需求安裝就可以了,像是如果是要用 CLI 去執行的就可以只安裝寫 Migrations 的部分就好。
FluentMigratorFluentMigrator.RunnerMicrosoft.Data.SqliteNpgsql建立一個名為 20200616_CreateUserTable 的檔案,在裡面寫一個 Class,他繼承 Migration 及實作 Up() 跟 Down() 兩個方法。檔名跟 Class 名稱不限制,但建議檔名前面版本,便於檢視。
接下來為這個 Class 加上 [Migration] Attribute,如 [Migration(<自訂版本>)],版本可自訂,用於決定執行順序,FluentMigrator 會依照這個版本號由小到大去執行。
在 Up() 中攥寫這個 Migration 要執行的動作,而 Down() 則是寫 Up() 反向的操作,是用來清除 Up() 所執行的效果。
[Migration(1)]
public class CreateUserTable: Migration
{
public override void Up()
{
// ...
}
public override void Down()
{
// ...
}
}
這個套件提供使用 Fluent Interface 的方式去定義要執行的操作 (如建表、修改欄位…等),幾乎可以不需要看文件就可以依照 IDE 提示寫出來。

假設我要建立帶有 id 及 name 欄位的 users 資料表,那我可以這樣寫:
Up() 中,使用 Create 去建立一個名為 users 的資料表,接下來使用 WithColumn 去定義兩個欄位。Down() 中,使用 Delete 去刪除這個資料表。[Migration(1)]
public class CreateUserTable: Migration
{
public override void Up()
{
Create.Table("users")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("name").AsString();
}
public override void Down()
{
Delete.Table("users");
}
}
一個 Migration 沒有限制只能做一件事,像是我可以一個 Migrstion 就建很多個資料表。
它命名的非常直覺,幾乎可以不用看文件直接照著打就可以完成。詳細也可參考 Fluent Syntax Schema Overview。
支援的操作及範例如下:
CreateCreate.Table("users")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("name").AsString();
AlterAlter.Table("users").AddColumn("account").AsString().Unique();
Rename// 將 users 改為 accounts
Rename.Table("users").To("accounts");
// 將 users.name 改為 users.fullname
Rename.Column("name").OnTable("users").To("fullname");
Delete // 刪除資料表
Delete.Table("users");
// 刪除欄位
Delete.Column("column1")
.Column("column2")
.FromTable("users");
// 刪除資料
Delete.FromTable("users")
.Row(new { name = "Admin" }); // 刪除 name = 'Admin' 的 rows
Insert Insert
.IntoTable("users")
.Row(new { name = "Admin" });
Update Update.Table("users")
.Set(new { name = "Administrator" })
.Where(new { name = "Admin" });
Execute Execute.Script("myscript.sql");
Execute.EmbeddedScript("UpdateLegacySP.sql");
Execute.Sql("DELETE TABLE users");
IfDatabase() // 只在 PostgreSQL 才建立 users
IfDatabase("Postgres")
.Create.Table("users")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("name").AsString();
執行的方式有提兩種供選擇,分別為 In-Process 與 CLI,如果沒有特殊需求,官方推薦是使用 In-Process 的方式執行 Migrations。
顧名思義就是跟主程式包再一起,以下是我把把官方的範例程式化簡後的樣子,主要就分為「設定服務」及「執行」兩部分而已,可以依照自己需求加到自己的專案中。
// 設定 DI 服務
var serviceProvider = new ServiceCollection()
.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddSQLite()
.WithGlobalConnectionString("Data Source=test.db")
.ScanIn(typeof(AddLogTable).Assembly).For.Migrations())
.AddLogging(lb => lb.AddFluentMigratorConsole())
.BuildServiceProvider(false);
// 取得 Runner
var runner = serviceProvider.GetRequiredService<IMigrationRunner>();
// 執行 Migrations
runner.MigrateUp();
以 .Net Core Web App 為例,就可以放在 Startup.cs 裡面,直接用它所提供的 ServiceCollection 去設定服務,就像這樣:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddSQLite()
.WithGlobalConnectionString("Data Source=test.db")
.ScanIn(typeof(AddLogTable).Assembly).For.Migrations())
}
public void Configure(IApplicationBuilder app, IMigrationRunner migrationRunner)
{
migrationRunner.MigrateUp();
}
}
也是可以直接在 Program.cs 中執行,視自己需求決定。
官方有提供 Command Line 的工具 FluentMigrator.DotNet.Cli,可以藉由他直接執行含有 Migrations 的 dll。
安裝 FluentMigrator.DotNet.Cli
dotnet tool install -g FluentMigrator.DotNet.Cli
安裝完後,就可以藉由執行 dotnet fm 來完成一些事。
執行 dotnet fm -h 叫出 help 就可以看到有哪些功能,沒有很複雜。
> dotnet fm -h
The external FluentMigrator runner that integrates into the .NET Core CLI tooling
Usage: dotnet-fm [options] [command]
Options:
-?|-h|--help Execute FluentMigrator actions
Commands:
list List stuff
migrate Apply migrations
rollback Rollback last migration
validate Validations
執行 Migration 是 dotnet fm migrate,完整指令如下:
dotnet fm migrate -p sqlite -c "Data Source=test.db" -a ".\bin\Debug\netcoreapp2.1\test.dll"
-p: Processor 類型,可以執行 dotnet fm list processors 查看所有的類型。-c: 連線字串-a: Assembly (dll),裡面要包含寫好的 Migrations。兩種方式執行結果是一樣的,就是會顯示執行過的 Migration 及執行資訊,並會在 DB 建一個 Table (預設名稱為:VersionInfo) 去紀錄,範例如下。
| Version | AppliedOn | Description |
|---|---|---|
| 20191114100000 | 2020-06-20 12:00:28.000000 | InitDB |
| 20191115110000 | 2020-06-20 12:00:28.000000 | AddUsersTable |
| 20191125100000 | 2020-06-20 12:00:28.000000 | AddRolesTable |
| 20191128100000 | 2020-06-20 12:00:28.000000 | AddPostsTable |
寫久了,如果遇到一次要做很多事情,但又不想相似的東西要寫 Up 及 Down 兩次,就可以改繼承 AutoReversingMigration,
之後一些單純的操作 (如建表…) 就不用寫 Down() 的部分,不過如果在使用上遇到某些方法找不到,就代表他是不支援的,就不能用 AutoReversingMigration 了。
[Migration(1)]
public class CreateUserTable: AutoReversingMigration
{
public override void Up()
{
Create.Table("users")
.WithColumn("id").AsInt32().PrimaryKey().Identity()
.WithColumn("name").AsString();
}
}
本篇文章同時發表於我的 Blog 中,歡迎到裡面查看我其他分享的文章。
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論