Search Results for

    Show / Hide Table of Contents

    This FAQ will answer most common questions. Please open an issue if your question isn't answered here.

    Why does the Migrate.exe tool say No migrations found?

    Possible reasons:

    • Migration class isn't public
    • Migration class isn't derived from IMigration (or Migration)
    • Migration class isn't attributed with MigrationAttribute
    • The versions of the Migrate.exe tool (FluentMigrator.Console package) and the FluentMigrator package(s) referenced in your project are different.

    How can I run FluentMigrator.DotNet.Cli with a .NET 5.0 assembly?

    The FluentMigrator.DotNet.Cli contains an --allowDirtyAssemblies switch that will allow you to load your 5.0 assemblies in a .NET Core 3.1 context. We're working on .NET 5.0 support.'

    Why do I get System.IO.FileLoadException: Could not load file or assembly 'FluentMigrator ...?

    If you get a stack trace like the following:

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileLoadException: Could not load file or assembly 'FluentMigrator, Version=3.2.1.0, Culture=neutral, PublicKeyToken=aacfc7de5acabf05". Could not find or load specific file.
    

    Then the most likely explanation is that you installed the FluentMigrator.DotNet.Cli command line tool globally, with a specific FluentMigrator.dll version in your global tool directory, and are loading a migrations assembly that references a different version of FluentMigrator.dll.

    The common workaround is to install the tool locally, rather than globally (applies to .NET Core SDK 3.0 and later).

    What are the supported databases?

    Database Identifier Alternative identifier(s)
    Microsoft SQL Server 2019 SqlServer2016(1) SqlServer
    Microsoft SQL Server 2017 SqlServer2016(2) SqlServer
    Microsoft SQL Server 2016 SqlServer2016 SqlServer
    Microsoft SQL Server 2014 SqlServer2014 SqlServer
    Microsoft SQL Server 2012 SqlServer2012 SqlServer
    Microsoft SQL Server 2008 SqlServer2008 SqlServer
    Microsoft SQL Server 2005 SqlServer2005 SqlServer
    Microsoft SQL Server 2000 SqlServer2000 SqlServer
    Microsoft SQL Server Compact Edition(3) SqlServerCe SqlServer
    PostgreSQL Postgres PostgreSQL
    PostgreSQL 9.2 Postgres92 PostgreSQL92
    PostgreSQL 10.0 PostgreSQL10_0 PostgreSQL
    PostgreSQL 11.0 PostgreSQL11_0 PostgreSQL
    MySQL 4 MySql4 MySql
    MySQL 5 MySql5 MySql, MariaDB
    Oracle Oracle
    Oracle (managed ADO.NET) OracleManaged Oracle
    Oracle (DotConnect ADO.NET) OracleDotConnect Oracle
    Microsoft JET Engine (Access) Jet
    SQLite Sqlite
    Firebird Firebird
    Amazon Redshift Redshift
    SAP Hana Hana
    SAP SQL Anywhere(4) SqlAnywhere16 SqlAnywhere
    DB2 DB2
    DB2 iSeries DB2 iSeries DB2
    • (1) All integration tests ran without error against an SQL Server 2019 using the SqlServer2016 dialect.
    • (2) All integration tests ran without error against an SQL Server 2017 using the SqlServer2016 dialect.
    • (3) Support for Microsoft SQL Server Compact Edition is being dropped due to Microsoft end-of-life support date passing.
    • (4) Support for SAP SQL Anywhere is being dropped due to SAP not supporting a .NET Core / .NET 5 database driver.

    How can I run migrations safely from multiple application servers?

    Many server-side applications are load balanced and run multiple instances of the same application simultaneously from multiple web servers. In such a scenarios, if you choose to run migrations in-process (as opposed to an external migration runner), then there is an added risk of multiple processes trying to run migrations at the same time.

    FluentMigrator does not automatically handle this scenario because the default transactional behavior is not enough to guarantee that only a single process can be running migrations at any given time. There are, however, some workarounds.

    Database-Dependent Application Locking

    This style of solution depends upon MaintenanceMigrations. Two Maintenance Migrations are created: One with BeforeAll to atomically acquire a lock, and one AfterAll stage to release the lock.

    This example is for SQL Server 2008 and above and uses sp_getapplock to aquire a named lock before all migrations are run, and sp_releaseapplock to release the lock after all migrations are finished.

    [Maintenance(MigrationStage.BeforeAll, TransactionBehavior.None)]
    public class DbMigrationLockBefore : Migration
    {
        public override void Down()
        {
            throw new NotImplementedException("Down migrations are not supported for sp_getapplock");
        }
    
        public override void Up()
        {
            Execute.Sql(@"
                DECLARE @result INT
                EXEC @result = sp_getapplock 'MyApp', 'Exclusive', 'Session'
    
                IF @result < 0
                BEGIN
                    DECLARE @msg NVARCHAR(1000) = 'Received error code ' + CAST(@result AS VARCHAR(10)) + ' from sp_getapplock during migrations';
                    THROW 99999, @msg, 1;
                END
            ");
        }
    }
    
    [Maintenance(MigrationStage.AfterAll, TransactionBehavior.None)]
    public class DbMigrationUnlockAfter : Migration
    {
        public override void Down()
        {
            throw new NotImplementedException("Down migrations are not supported for sp_releaseapplock");
        }
    
        public override void Up()
        {
            Execute.Sql("EXEC sp_releaseapplock 'MyApp', 'Session'");
        }
    }
    

    In the above SQL Server example, we need to use TransactionBehavior.None on the Maintenance Migration while specifying the @LockOwner parameter to Session, which means that the locking behavior applies to the entire Session rather than a single transaction.

    While the above is specific to SQL Server, similar concepts may available in other database providers.

    • PostgreSQL has Advisory Locks
    • SQL Anywhere has Schema Locks
    • Oracle has DBMS_LOCK.ALLOCATE_UNIQUE
    • DB2 has LOCK TABLESPACE (with the caveat that every table in your migration is in the same tablespace)

    External Distributed Lock

    If your database doesn't provide a means of acquiring an exclusive lock for migrations, it is still possible to achieve this functionality by using an external service for acquiring a distributed lock.

    For example, Redis provides a way to perform Distributed locks so that different processes can operate on a shared resource in a mutually exclusive way. This scenario can be baked into a BeforeAll/AfterAll pair of Maintenance Migrations, as demonstrated above, to acquire an exclusive lock for the duration of the migration running.

    As an alternative to Maintenance Migrations, which are by necessity specified in different classes, you could simply wrap the MigrateUp() call in code that acquires and releases the lock. Consider this pseudo-code which relies on RedLock.net:

    async RunMigrationsWithDistributedLock(IMigrationRunner runner)
    {
        var resource = "my-app-migrations";
        var expiry = TimeSpan.FromMinutes(5);
    
        using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry)) // there are also non async Create() methods
        {
            // make sure we got the lock
            if (redLock.IsAcquired)
            {
                runner.MigrateUp();
            }
        }
        // the lock is automatically released at the end of the using block
    }
    

    How can I execute a stored procedure using Oracle?

    If you get ORA-00900: Invalid SQL Statement when executing a stored procedure, then chances are you need to wrap your stored procedure in a PLSQL block:

      Execute.Sql("DBMS_UTILITY.EXEC_DDL_STATEMENT('Create Index Member_AddrId On Member(AddrId)');");
    

    becomes:

      Execute.Sql(@"
    BEGIN
      DBMS_UTILITY.EXEC_DDL_STATEMENT('Create Index Member_AddrId On Member(AddrId)');
    END;");
    

    How do I get the name of a SQL Server database?

    Not all databases have a "name". Writing migrations that use a name therefore cannot be truly database-agnostic. That said, the following will show an example of getting the name so that you can perform an ALTER DATABASE command. Note that to ALTER DATABASE [YourDatabaseName], you need to switch to the [master] database first via USE [master]. Then, since FluentMigrator does not call sp_reset_connection, you need to switch back to the database being migrated. If you do not, the ensuing migrations will be run in the wrong database!

    In the below example, we show how to enter a SQL Server database into single-user mode, in order to perform some maintenace tasks.

    Use dynamic SQL:

        public class EnterDatabaseSingleUserModeState : Migration
        {
            public override void Up()
            {
                /* Before you set the database to SINGLE_USER, verify that
                the AUTO_UPDATE_STATISTICS_ASYNC option is set to OFF. When
                this option is set to ON, the background thread that is
                used to update statistics takes a connection against the
                database, and you will be unable to access the database in
                single-user mode. For more information, see
                ALTER DATABASE SET Options (Transact-SQL). */
                this.Execute.Sql(@"
                  DECLARE @DbName sysname = DB_NAME();
                  DECLARE @SqlCommand NVARCHAR(MAX) = '
    USE [master];
    SET DEADLOCK_PRIORITY 10;
    DECLARE @AutoUpdateStatisticsAsync BIT = CAST(0 AS BIT);
    IF EXISTS (
        SELECT NULL
        FROM sys.databases WHERE name = @DbName AND is_auto_update_stats_async_on = CAST(1 AS BIT)
    )
    BEGIN
        ALTER DATABASE [' + @DbName + '] 
        SET AUTO_UPDATE_STATISTICS_ASYNC OFF;
        SET @AutoUpdateStatisticsAsync = CAST(1 AS BIT);
    END;
    ALTER DATABASE [' + @DbName + ']' + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    
    -- Here is where you put your administrative commands.
    
    IF (@AutoUpdateStatisticsAsync = 1)
    BEGIN
        ALTER DATABASE [' + @DbName + '] 
        SET AUTO_UPDATE_STATISTICS_ASYNC ON;
    END;
    ';
                  
                  EXEC(@SqlCommand);
                  SET @SqlCommand NVARCHAR(MAX) = 'USE [' + @DbName + ']';
                  EXEC(@SqlCommand);
                ");
        }
    

    Certificate error for SQL Connection

    Since the use of Microsoft.Data.SqlClient version 4.0.0 connections are encrypted by default in .NET. You might start getting the exception: A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.). If fixing a valid certificate isn't a feasable path, you can always disable the encryption by adding Encrypt=False to the connection string. Then the connection won't be encryptet, and thus no certificate needed. As a note; you can also add TrustServerCertificate=True to the connection string, if you have a self-signed certificate or similar. But it's probably a better idea to fix a real certificate, or skip encryption all together.

    SQLite specific topics

    Connection Pooling

    When working with FluentMigrator with the SQLite processor, by default SQLite will run with connection pooling enabled. When connection pooling is enabled, SQLite will keep a lock on the database file even after connection.Close() is called on the relevant DB connection. This is important to know in case you need to perform any cleanup after FluentMigrator has run where deleting the database file is required. In this scenario you would receive an IO exception if you attempt to delete or move the file as SQLite still has a lock on the file.

    You can disable connection pooling however by adding Pooling=False; as a parameter in your connection string. With pooling disabled, you can then safely delete or move the database after the FluentMigrator processor is disposed.

    • Improve this Doc
    In This Article
    Back to top
    Copyright © 2018 Fluent Migrator Project
    Generated by DocFX
    Creative Commons License
    FluentMigrator Documentation by FluentMigrator Project is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.