動態

詳情 返回 返回

深入掌握 FluentMigrator:C#.NET 數據庫遷移框架詳解 - 動態 詳情

簡介

概念定位

  • FluentMigrator 是一個基於 “流式 API”Fluent API)的 .NET 數據庫版本遷移框架。
  • 核心目標:以代碼形式對數據庫結構(Schema)進行增量變更管理,支持 SQL Server、PostgreSQL、MySQL、SQLite、Oracle 等多種數據庫。
  • 核心優勢:

    1. 可讀性高:以鏈式方法描述表、列、索引等,而非手寫 SQL
    2. 可編程:可藉助 C# 邏輯(條件、循環)來生成遷移;
    3. 可版本化:每個遷移都有唯一版本號,保證在不同環境中有序執行;
    4. 可回滾:內置 Down 方法,支持自動回退。

核心價值

  1. 傳統 SQL 腳本管理的痛點
問題 影響 FluentMigrator 解決方案
腳本執行順序混亂 數據庫狀態不一致 版本號強制順序執行
環境差異處理困難 開發/測試/生產不一致 代碼統一管理所有環境
回滾機制缺失 錯誤修復困難 支持 Up/Down 雙向遷移
狀態追蹤困難 不知當前數據庫版本 內置版本追蹤表
團隊協作衝突 合併衝突頻發 代碼合併更簡單
  1. 核心優勢
graph TD
    A[FluentMigrator] --> B[純代碼遷移]
    A --> C[多數據庫支持]
    A --> D[版本控制集成]
    A --> E[環境無關設計]
    A --> F[自動回滾機制]
    B --> G[C#強類型安全]
    C --> H[SQL Server<br>PostgreSQL<br>MySQL<br>SQLite]
    D --> I[Git/SVN友好]

安裝與配置

  1. NuGet 引入

在項目(建議單獨建一個 Migrations 項目)中安裝:

dotnet add package FluentMigrator
dotnet add package FluentMigrator.Runner
dotnet add package FluentMigrator.Runner.SqlServer
dotnet add package FluentMigrator.Runner.MySql

注意先得有 ADO 驅動包,例如:MySql.Data

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net9.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="FluentMigrator" Version="7.1.0" />
      <PackageReference Include="FluentMigrator.Runner" Version="7.1.0" />
      <PackageReference Include="FluentMigrator.Runner.MySql" Version="7.1.0" />
      <PackageReference Include="MySql.Data" Version="9.4.0" />
    </ItemGroup>

</Project>

若要在 .NET Core CLI 中使用,可額外安裝:

dotnet tool install --global FluentMigrator.DotNet.Cli
  1. 配置 Runner

.NET Core 控制枱或 ASP.NET CoreProgram.cs 中:

using FluentMigrator.Runner;

var serviceProvider = new ServiceCollection()
    .AddFluentMigratorCore()
    .ConfigureRunner(rb => rb
        .AddSqlServer()                                    // 指定數據庫類型
        .WithGlobalConnectionString(Configuration.GetConnectionString("Default"))
        .ScanIn(typeof(Program).Assembly).For.Migrations()
    )
    .AddLogging(lb => lb.AddFluentMigratorConsole())       // 控制枱日誌
    .BuildServiceProvider();

// 執行遷移
using var scope = serviceProvider.CreateScope();
var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
runner.MigrateUp();   // 或 runner.MigrateDown(targetVersion);

核心概念

  • Migration(遷移類)

    • 每個遷移類繼承自 Migration,通過 Version 屬性或構造參數指定版本號(通常為 yyyyMMddHHmm 形式)。
    • 重寫 Up()Down() 方法,分別描述版本升級和降級的操作。
  • Runner(運行器)

    • IMigrationRunner 提供執行、回滾、版本查詢等功能。
    • 通過依賴注入或 CLI 工具觸發。
  • 版本表

    • 默認在數據庫中維護一張 VersionInfo 表,用於存儲已執行的遷移版本號集合。

創建與執行遷移

編寫遷移

[Migration(202507150901)]
public class CreateUsersTable : Migration
{
    public override void Up()
    {
        Create.Table("Users")
            .WithColumn("Id").AsInt32().PrimaryKey().Identity()
            .WithColumn("Username").AsString(100).NotNullable()
            .WithColumn("Email").AsString(200).Nullable()
            .WithColumn("CreatedAt").AsDateTime().WithDefault(SystemMethods.CurrentUTCDateTime);
    }

    public override void Down()
    {
        Delete.Table("Users");
    }
}
  • Create.Table()、.WithColumn()、.AsXxx():流式構造表結構。
  • SystemMethods.CurrentUTCDateTime:框架內置常用 SQL 函數。

執行遷移(CLI)

常用命令參數

參數 説明 示例
-c 連接字符串 -c "Server=.;Database=Test;..."
-p 數據庫提供程序 -p sqlserver2016
-a 遷移程序集 -a "Migrations.dll"
-t 版本號 -t 202306010002
-o 輸出 SQL 到文件 -o migrations.sql
--preview 預覽模式 --preview

遷移文件詳解

基本遷移結構

[Migration(202305010001)] // 唯一版本號
public class InitialSchema : Migration
{
    public override void Up()
    {
        // 升級操作
        Create.Table("Users")
            .WithColumn("Id").AsInt32().PrimaryKey().Identity()
            .WithColumn("Name").AsString(100).NotNullable()
            .WithColumn("CreatedAt").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime);
    }

    public override void Down()
    {
        // 回滾操作
        Delete.Table("Users");
    }
}

常用操作示例

創建表

Create.Table("Products")
    .WithColumn("Id").AsInt32().PrimaryKey().Identity()
    .WithColumn("Name").AsString(100).NotNullable()
    .WithColumn("Price").AsDecimal(10, 2).NotNullable()
    .WithColumn("CategoryId").AsInt32().ForeignKey("Categories", "Id");

修改表結構

Alter.Table("Users")
    .AddColumn("LastLogin").AsDateTime().Nullable()
    .AlterColumn("Name").AsString(150).NotNullable();

創建索引

Create.Index("IX_Users_Email")
    .OnTable("Users")
    .OnColumn("Email").Ascending()
    .WithOptions().Unique()
    .WithOptions().NonClustered();

數據遷移

Insert.IntoTable("AuditLog")
    .Row(new { Action = "PriceUpdate", UserId = 1, Timestamp = DateTime.UtcNow });

執行自定義 SQL

[Migration(2025071505)]
public class CustomSqlMigration : Migration
{
    public override void Up()
    {
        Execute.Sql("UPDATE Users SET Age = Age + 1 WHERE Name LIKE 'J%'");
    }

    public override void Down()
    {
        Execute.Sql("UPDATE Users SET Age = Age - 1 WHERE Name LIKE 'J%'");
    }
}

高級特性

事務控制

[Migration(202306010003, TransactionBehavior.None)] // 禁用事務
public class LargeDataMigration : Migration
{
    public override void Up()
    {
        // 大數據遷移操作(分批次執行)
        Execute.WithConnection((conn, trans) => 
        {
            // 手動事務控制
            using var cmd = conn.CreateCommand();
            cmd.CommandText = "INSERT ...";
            cmd.ExecuteNonQuery();
        });
    }
}

環境特定遷移

[Migration(202306150004)]
[Tags("Development", "Staging")] // 只應用於特定環境
public class AddTestData : Migration
{
    public override void Up()
    {
        if (ApplicationEnvironment.Current == "Development")
        {
            Insert.IntoTable("Users")
                .Row(new { Name = "TestUser", Email = "test@example.com" });
        }
    }
}

條件遷移

  • 使用 IfDatabase() 適配不同數據庫:
IfDatabase("SqlServer").Create.Table("Users").WithColumn("Id").AsInt32();

集成 CI/CD

  • 在啓動時運行遷移,或使用 dotnet fm 工具
dotnet fm migrate -p sqlite -c "Data Source=test.db" -a Migrations.dll

自定義遷移基類

public abstract class AuditMigration : Migration
{
    protected void AddAuditColumns(string tableName)
    {
        Alter.Table(tableName)
            .AddColumn("CreatedBy").AsString(50).NotNullable().WithDefaultValue("system")
            .AddColumn("CreatedAt").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime)
            .AddColumn("UpdatedBy").AsString(50).Nullable()
            .AddColumn("UpdatedAt").AsDateTime().Nullable();
    }
}

[Migration(202307010005)]
public class AddAuditToProducts : AuditMigration
{
    public override void Up() => AddAuditColumns("Products");
}

數據庫特定語法

public override void Up()
{
    IfDatabase("sqlserver").Create.Column("RowVersion").OnTable("Users").AsCustom("ROWVERSION");
    IfDatabase("postgres").Create.Column("RowVersion").OnTable("Users").AsInt64().WithDefaultValue(0);
}

回滾與版本控制

  • 回滾策略

    • runner.MigrateDown(long version):回退到指定版本,所有高於該版本的 Up 操作都會執行其 Down。
    • runner.Rollback(int steps):回退指定步數。
  • 版本表管理

    • 遷移執行後,Runner 會在 VersionInfo 表中插入記錄。
    • 手動清理、或在測試數據庫初始化時,可先 runner.ListMigrations()、再 runner.MigrateDown(0) 全部回滾。

進階特性

標籤(Tags)

  • 可給遷移打標籤,按環境有選擇地執行:
[Migration(202507150901, TransactionBehavior.Default, "dev","test")]
public class DevOnlyMigration : Migration { … }
  • Runner 執行時傳入 Tags = new[] { "test" },只運行標記匹配的遷移。

事務控制

  • 默認每個 Up()/Down() 在單個事務中執行,可通過 TransactionBehavior.None 禁用事務包裹。

自定義腳本與模板

  • Up() 中可調用 Execute.Sql("…"),執行任意 SQL
  • 支持加載嵌入資源腳本:
Execute.EmbeddedScript("Namespace.Scripts.SeedData.sql");

多數據庫分支

  • 通過條件判斷在 Up() 中針對不同 RunnerContext.Provider 執行不同邏輯,實現一個遷移類多庫支持。

Preview 與 Dry‑Run

  • 使用日誌器攔截生成的 SQL,而不真正執行,適合代碼 review 或審計。

與 Entity Framework 遷移對比

特性 FluentMigrator EF Core Migrations
數據庫支持 廣泛(20+種) 主流數據庫
ORM 依賴 依賴 EF Core
遷移控制 精確控制 自動生成
複雜操作 支持原生 SQL 限制較多
版本管理 顯式版本號 自動排序
回滾能力 完整 Down 腳本 部分支持
適用場景 複雜企業系統 EF Core 項目

最佳實踐

  1. 版本號規範

    • 建議使用 UTC 時間戳(如 202507150901),保證版本唯一且可排序。
  2. 小步提交

    • 每個遷移專注一個功能點,避免合併衝突。
  3. 編寫 Down

    • 同步維護 Down() 方法,以便緊急回退;如果不支持,可在類上標記跳過回滾。
  4. 環境隔離

    • 在測試/本地環境使用內存或專用數據庫,避免干擾生產。
  5. 審計與審查

    • 將遷移代碼納入代碼審查流程,必要時開啓 Dry‑Run,打印 SQL 預覽。
  6. 腳本化種子數據

    • 如需初始化必備字典表,可在遷移中引入嵌入式 SQL 腳本而非硬編碼。

資源與擴展

  • GitHub:https://github.com/fluentmigrator/fluentmigrator
  • 文檔:https://fluentmigrator.github.io
  • NuGet 包:

    • FluentMigrator:核心遷移框架。
    • FluentMigrator.Runner:運行器。
    • FluentMigrator.Runner.SqlServer:SQL Server 支持。
  • 擴展工具:

    • Alt.FluentMigrator.VStudio:Visual Studio 集成,簡化遷移生成。
    • dotnet-fm:命令行工具,執行遷移。
user avatar yushang_66b0e8718bd85 頭像 kindledawn 頭像 damenge 頭像 rui_sen 頭像 abelethan 頭像 saxiaoyige 頭像 aitaokedemiehuoqi 頭像
點贊 7 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.