Search code examples
c#.net-core-3.1fluent-migrator

Get content of pending migrations using FluentMigrator


I have console app that uses FluentMigrator migrations, but now I need to implement user confirmation before actual migration process. I got into repo sources, found out about version loader and how to get unapplied list of migrations using IServiceProvider. But can't find a way yet to print SQL script of the migration that will be used in the MigrateUp(). I am using SQL Server package as well. Could anyone point a direction?

private static void UpdateDatabase(IServiceProvider serviceProvider)
{
    var runner = serviceProvider.GetRequiredService<IMigrationRunner>();
    var versionLoader = serviceProvider.GetRequiredService<IVersionLoader>();
    var migrationContext = serviceProvider.GetRequiredService<IMigrationContext>();

    var migrations = runner.MigrationLoader.LoadMigrations()
        .Where(migration => !versionLoader.VersionInfo.HasAppliedMigration(migration.Key))
        .ToList();

    // print migrations up expressions
    foreach (var migration in migrations)
    {
        Console.WriteLine($"Pending migration: {migration.Value.GetName()}");
        Console.WriteLine("SQL:");

        migration.Value.Migration.GetUpExpressions(migrationContext);

        foreach (var expression in migrationContext.Expressions)
        {
            Console.WriteLine(expression); // this just outputs "CreateTable Test" in my case
        }
    }

    bool userAccepted = true; // TODO: get confirmation from user

    if (!userAccepted)
        return;

    // Execute the migrations
    runner.MigrateUp();
}

Solution

  • There is IMigrationGenerator that can be resolved by using IServiceProvider. But, unfortunately, there are no methods that support IMigrationExpression parameter (see below), so I had to write either wall of if-else statements for each type or use a reflection. I used second option. Maybe there is better approach?

    enter image description here

    var migrationGenerator = serviceProvider.GetRequiredService<IMigrationGenerator>();
    
    // print migrations up expressions
    foreach (var migration in migrations)
    {
        Console.WriteLine($"Pending migration: {migration.Value.GetName()}");
        Console.WriteLine("SQL:");
    
        migration.Value.Migration.GetUpExpressions(migrationContext);
    
        foreach (var expression in migrationContext.Expressions)
        {
            if (expression is ExecuteSqlScriptExpression executeSqlScriptExpression)
            {
                Console.WriteLine(executeSqlScriptExpression.SqlScript);
            }
            else if (expression is ExecuteSqlStatementExpression executeSqlStatementExpression)
            {
                Console.WriteLine(executeSqlStatementExpression.SqlStatement);
            }
            else
            {
                var processMethod = migrationGenerator.GetType().GetMethod("Generate", new[] { expression.GetType() });
                var sql = (string)processMethod.Invoke(migrationGenerator, new[] { expression });
    
                Console.WriteLine(sql);
            }
        }
    }