public void Filter(MigrationMapStateInfo databaseMigrationState)
        {
            MigrationFilterContext context = new MigrationFilterContext()
            {
                MigrationNodes = databaseMigrationState.MigrationNodesInfo
            };

            foreach (var filter in this.Filters)
            {
                filter.Filter(context);
            }
        }
        public void Migrate()
        {
            output.EventBegin("migration", "Migration");

            //upgrade the schema to be updated
            output.Info("Checking Core Schema");
            dataProvider.UpgradeSchema();


            //get nodes
            output.EventBegin("map-load", "Migration Map Load");
            var map = mapProvider.GetMigrationMap();

            if (map.Identifier != null)
            {
                this.identifier = map.Identifier;
            }
            if (this.identifier == null)
            {
                throw new InvalidOperationException("Could not define a valid identifier for the migrator.");
            }

            var allMigrationsCount = map.MigrationNodes.SelectMany(x => x.Migrations).Count();

            output.Info(string.Format("{0} migrations found.", allMigrationsCount));
            output.EventEnd("map-load", "Migration Map Load");

            //get nodes current state in the selected database
            output.Info("Checking Migration Map State");
            var databaseMigrationState = GetState(map);

            //filter nodes
            MigrationFilterContext filterContext = new MigrationFilterContext()
            {
                MigrationNodes = databaseMigrationState.MigrationNodesInfo
            };

            output.EventBegin("filtering", "Node Filtering");
            foreach (var migrationFilter in migrationFilters)
            {
                output.Info("Filtering Nodes with filter " + migrationFilter.GetType().Name);
                migrationFilter.Filter(filterContext);
            }
            output.EventEnd("filtering", "Node Filtering");

            var migrationsToExecuteCount = databaseMigrationState.MigrationNodesInfo.SelectMany(x => x.MigrationsInfo).Where(x => x.CurrentState == Migration.MigrationState.ToUpgrade).Count();

            output.EventBegin("summary", "Migration Plan", migrationsToExecuteCount + " migrations.");
            foreach (var migration in databaseMigrationState.MigrationNodesInfo.SelectMany(x => x.MigrationsInfo).Where(x => x.CurrentState == Migration.MigrationState.ToUpgrade))
            {
                output.Info(string.Format(" - {0}", migration.Migration.Identifier));
            }
            output.EventEnd("summary", "Migration Plan");

            output.EventBegin("transaction", "Transaction");

            bool transactionCommited = false;

            using (var transactionScope = new TransactionScope()
                   ){
                //migrate
                bool stopNodeProcessing = false;
                bool hasErrors          = false;

                int migratedNodes = 0;
                int markedNodes   = 0;

                foreach (var nodeInfo in databaseMigrationState.MigrationNodesInfo)
                {
                    if (stopNodeProcessing)
                    {
                        break;
                    }

                    var node = nodeInfo.MigrationNode;
                    foreach (var migrationInfo in nodeInfo.MigrationsInfo)
                    {
                        if (stopNodeProcessing)
                        {
                            break;
                        }

                        if (migrationInfo.CurrentState == Migration.MigrationState.ToUpgrade)
                        {
                            bool jumpCurrentExecution = false;
                            bool markExecution        = true;


                            var migration = migrationInfo.Migration;

                            var migratingContext = new OnMigratingContext {
                                Migration = migration
                            };
                            onMigrating(migratingContext);
                            switch (migratingContext.Decision)
                            {
                            case OnMigratingDecision.Run: { break; }

                            case OnMigratingDecision.Stop: { stopNodeProcessing = true; jumpCurrentExecution = true; markExecution = false; break; }

                            case OnMigratingDecision.Jump: { jumpCurrentExecution = true; markExecution = false; break; }

                            case OnMigratingDecision.JumpAndMark: { jumpCurrentExecution = true; markExecution = true; break; }

                            default: { throw new NotImplementedException(); }
                            }

                            string sql = string.Empty;
                            sql = migration.GetUpgradeSql();

                            if (!jumpCurrentExecution)
                            {
                                try
                                {
                                    output.Info("Executing script " + migration.Identifier);
                                    dataProvider.ExecuteSql(sql);
                                    migratedNodes++;
                                }
                                catch (Exception ex)
                                {
                                    hasErrors = true;
                                    var migrationErrorContext = new OnMigrationErrorContext {
                                        Migration = migration, Exception = ex
                                    };
                                    onMigrationError(migrationErrorContext);
                                    switch (migrationErrorContext.Decision)
                                    {
                                    case OnMigrationErrorDecision.Stop: { stopNodeProcessing = true; markExecution = false; break; }

                                    case OnMigrationErrorDecision.MarkAnywayAndStop: { stopNodeProcessing = true; break; }

                                    case OnMigrationErrorDecision.Continue: { markExecution = false; break; }

                                    case OnMigrationErrorDecision.MarkAnywayAndContinue: { markExecution = true; break; }

                                    default: { throw new NotImplementedException(); }
                                    }
                                }
                            }

                            if (markExecution)
                            {
                                dataProvider.InsertExecutedMigration(new DataAccess.Entities.ExecutedMigration()
                                {
                                    LastRunScript     = sql,
                                    LastRunDate       = DateTime.Now,
                                    MigrationId       = migration.Identifier,
                                    MigrationNodeId   = node.Identifier,
                                    MigrationRunnerId = this.identifier
                                });
                                markedNodes++;
                            }
                        }
                    }
                }
                if (migratedNodes == 0 && markedNodes == 0)
                {
                    output.Info("Nothing to commit or rollback.");
                }
                else
                {
                    var onCompletingTransactionContext = new OnCompletingTransactionContext()
                    {
                        HasErrors = hasErrors
                    };
                    onCompletingTransaction(onCompletingTransactionContext);
                    switch (onCompletingTransactionContext.Decision)
                    {
                    case OnCompletingTransactionDecision.Commit: {
                        output.Info("Commiting...");
                        transactionScope.Complete();
                        transactionCommited = true;
                        //set resolved root
                        break;
                    }

                    case OnCompletingTransactionDecision.Rollback: {
                        output.Info("Rolling back...");
                        break;
                    }

                    default: { throw new NotImplementedException(); }
                    }
                }
            }
            output.EventEnd("transaction", "Transaction");

            foreach (var migrationFilter in migrationFilters)
            {
                migrationFilter.AfterTransaction(transactionCommited);
            }


            output.EventEnd("migration", "Migration");
        }