private static MigrationRunner GetMigrationRunner(StringWriter sw, MigrateDatabaseContext dbItem, Assembly migrationAssembly)
        {
            Announcer announcer = new TextWriterWithGoAnnouncer(sw)
            {
                ShowSql = true
            };

            var runnerCtx = new RunnerContext(announcer)
            {
                ApplicationContext = dbItem
            };

            if (string.IsNullOrWhiteSpace(dbItem.CurrentDatabaseNamespace))
            {
                throw new ArgumentNullException(nameof(dbItem.CurrentDatabaseNamespace), "<DatabaseNamespace> should not null or empty");
            }

            runnerCtx.Namespace = dbItem.CurrentDatabaseNamespace;

            var options = new ProcessorOptions {
                PreviewOnly = false, Timeout = dbItem.ConnectionTimeout
            };
            var factory = new FluentMigrator.Runner.Processors.SqlServer.SqlServer2014ProcessorFactory();

            using (var processor = factory.Create(dbItem.ConnectionString, announcer, options))
            {
                return(new MigrationRunner(migrationAssembly, runnerCtx, processor));
            }
        }
        /// <summary>
        /// Run migration for specific database
        /// </summary>
        /// <param name="runner"></param>
        /// <param name="dbContext"></param>
        public static void Process(this ExtMigrationRunner runner, MigrateDatabaseContext dbContext, bool forceApplyScripts)
        {
            if (!forceApplyScripts && runner.HasInvaildScripts)
            {
                Logger.Info("There is some invaild scripts, if you want to force apply them, you must config forceApplyScripts = true");
                return;
            }

            Logger.InfoFormat($"DATEBASE: {dbContext.DatabaseKey} ({dbContext.DatabaseName})");
            #region Check settings

            if (runner.DatabaseScriptTypes == null)
            {
                throw new ArgumentNullException(nameof(runner.DatabaseScriptTypes), "Value should not null");
            }

            if (runner.MigrationAssembly == null)
            {
                throw new ArgumentNullException(nameof(runner.MigrationAssembly), "Value should not null");
            }

            #endregion

            try
            {
                foreach (var scriptType in runner.DatabaseScriptTypes)
                {
                    ApplyMigrationUp(dbContext, scriptType.Value, runner.MigrationAssembly);
                }

                Logger.InfoFormat($"=> [{dbContext.DatabaseKey}] is done");
                Logger.InfoFormat(Environment.NewLine);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw;
            }
        }
        private static void ApplyMigrationUp(MigrateDatabaseContext dbContext, DatabaseScriptType scriptType, Assembly migrationAssembly)
        {
            using (var sw = new StringWriter())
            {
                var migRunner  = GetMigrationRunner(sw, dbContext, migrationAssembly);
                var migrations = migRunner.MigrationLoader.LoadMigrations();

                var printAtStart = false;
                foreach (var script in migrations)
                {
                    if (!script.Value.Version.ToString().StartsWith(((int)scriptType).ToString()))
                    {
                        continue;
                    }

                    var migrateAttr =
                        script.Value.Migration.GetType()
                        .GetCustomAttributes(typeof(BaseExtMgrAttribute), false)
                        .FirstOrDefault();

                    if (migrateAttr == null || migRunner.VersionLoader.VersionInfo.HasAppliedMigration(script.Value.Version))
                    {
                        continue;
                    }

                    // exclude invaild script
                    if (!ExtMigrationRunner.ValidScriptsStore.Contains($"{script.Value.Version}.{dbContext.DatabaseKey}"))
                    {
                        continue;
                    }

                    switch (scriptType)
                    {
                    case DatabaseScriptType.SqlDataStructureFunction:
                        if (!(migrateAttr is ExtMgrDataStructureAndFunctionsAttribute))
                        {
                            continue;
                        }
                        break;

                    case DatabaseScriptType.SqlStoredProcedures:
                        if (!(migrateAttr is ExtMgrStoredProceduresAttribute))
                        {
                            continue;
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(scriptType), scriptType, null);
                    }

                    if (!printAtStart)
                    {
                        Logger.InfoFormat($" > {scriptType.GetEnumDescription()}");
                        printAtStart = true;
                    }

                    Logger.InfoFormat($"   - {script.Value.Version} - {script.Value.Migration.GetType().Name} {(!((BaseExtMgrAttribute)migrateAttr).UseTransaction ? " -noTrans" : string.Empty)}");

                    migRunner.ApplyMigrationUp(script.Value, ((BaseExtMgrAttribute)migrateAttr).UseTransaction);
                }
            }
        }