You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中条件执行Fluent Migrator脚本?区分桌面与服务迁移表

如何通过Fluent Migrator区分桌面程序与Windows服务的迁移执行

刚好我之前处理过类似的场景,结合你已经用到的[Tags]属性,分两种情况给你梳理解决方案:

场景1:同一文件内拆分不同迁移类(推荐方案)

如果只是想把桌面和服务负责的表创建逻辑放在同一个文件里,最稳妥的方式是拆分两个独立的迁移类,分别标记对应标签:

比如在M01_CreateTables.cs文件中:

// 桌面程序负责创建的表,标记desktop标签
[Tags("desktop")]
[Migration(101)]
public class M01_CreateDesktopTables : ForwardOnlyMigration
{
    public override void Up()
    {
        // 创建桌面专属表,比如配置表
        Create.Table("AppConfig")
              .WithColumn("Id").AsInt32().PrimaryKey().Identity()
              .WithColumn("ConfigKey").AsString(50).NotNullable()
              .WithColumn("ConfigValue").AsString(200).NotNullable();
    }
}

// Windows服务负责创建的表,标记service标签
[Tags("service")]
[Migration(102)]
public class M02_CreateServiceTables : ForwardOnlyMigration
{
    public override void Up()
    {
        // 创建服务专属表,比如任务日志表
        Create.Table("TaskLog")
              .WithColumn("Id").AsInt32().PrimaryKey().Identity()
              .WithColumn("TaskName").AsString(100).NotNullable()
              .WithColumn("LogContent").AsString(2000).NotNullable();
    }
}

接下来在桌面程序和服务中分别指定要执行的标签:

  • 桌面程序端执行迁移:

    // 初始化Fluent Migrator Runner(根据你的数据库类型调整,比如SqlServer)
    var runner = new RunnerBuilder()
        .AddSqlServer()
        .WithGlobalConnectionString("你的数据库连接字符串")
        .Build();
    
    // 只运行标记了desktop标签的迁移
    runner.MigrateUp(new MigrationOptions { Tags = new[] { "desktop" } });
    
  • Windows服务端执行迁移:

    var runner = new RunnerBuilder()
        .AddSqlServer()
        .WithGlobalConnectionString("你的数据库连接字符串")
        .Build();
    
    // 只运行标记了service标签的迁移
    runner.MigrateUp(new MigrationOptions { Tags = new[] { "service" } });
    

这种方式的好处是桌面和服务的迁移逻辑完全独立,Fluent Migrator的版本记录表(默认__MigrationHistory)会分别追踪各自的迁移状态,不会出现重复执行或遗漏的问题。

场景2:同一迁移类内区分执行逻辑(不推荐)

如果确实要在同一个Migration类里拆分桌面和服务的操作,可以通过自定义上下文参数来判断执行环境,但要注意迁移版本的唯一性问题:

首先在初始化Runner时传入执行环境标记:

  • 桌面程序端:

    var migrationContext = new MigrationContext();
    migrationContext.Items["ExecutionEnv"] = "desktop";
    
    var runner = new RunnerBuilder()
        .AddSqlServer()
        .WithGlobalConnectionString("你的连接字符串")
        .WithMigrationContext(migrationContext)
        .Build();
    
    runner.MigrateUp();
    
  • 服务端同理,把ExecutionEnv设为service。

然后在迁移类的Up方法里做条件判断:

[Migration(103)]
public class M03_MixedMigration : ForwardOnlyMigration
{
    public override void Up()
    {
        var executionEnv = Context.Items["ExecutionEnv"] as string;

        // 仅桌面程序执行的表创建
        if (executionEnv == "desktop")
        {
            Create.Table("UserSetting")
                  .WithColumn("Id").AsInt32().PrimaryKey().Identity()
                  .WithColumn("UserId").AsInt32().NotNullable()
                  .WithColumn("SettingValue").AsString(100).NotNullable();
        }

        // 仅服务执行的表创建
        if (executionEnv == "service")
        {
            Create.Table("JobQueue")
                  .WithColumn("Id").AsInt32().PrimaryKey().Identity()
                  .WithColumn("JobType").AsString(50).NotNullable()
                  .WithColumn("JobData").AsString(500).NotNullable();
        }
    }
}

⚠️ 注意:这种方式有个坑——Fluent Migrator是按迁移版本号来标记执行状态的。桌面执行完这个版本的迁移后,服务再运行时会发现该版本已经被标记为已执行,不会再进入Up方法,导致服务需要创建的表不会被创建。所以除非你有特殊需求,否则优先用第一种标签拆分迁移类的方案。

额外提示

你原来代码里的[Tags("service")] [Tags("config")]是给迁移类标记多个标签,执行时只要匹配其中一个标签就会运行。如果需要精确区分,建议给桌面和服务分别用唯一标签(比如desktop和service),避免交叉触发。

内容的提问来源于stack exchange,提问作者user2496448

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:28:39