/// <summary>
        /// Runs the plugin migrations for the specified plugin assembly
        /// </summary>
        /// <param name="pluginAssembly">The plugin assembly.</param>
        /// <returns></returns>
        /// <exception cref="RockStartupException">
        /// The '{assemblyName}' plugin assembly contains duplicate migration numbers ({ migrationNumberAttr.Number}).
        /// or
        /// ##Plugin Migration error occurred in {assemblyMigrations.Key}, {migrationType.Value.Name}##
        /// </exception>
        public static bool RunPluginMigrations(Assembly pluginAssembly)
        {
            string pluginAssemblyName = pluginAssembly.GetName().Name;

            // Migrate any plugins from the plugin assembly that have pending migrations
            List <Type> pluginMigrationTypes = Rock.Reflection.SearchAssembly(pluginAssembly, typeof(Rock.Plugin.Migration)).Select(a => a.Value).ToList();

            // If any plugin migrations types were found
            if (!pluginMigrationTypes.Any())
            {
                return(false);
            }

            bool result = false;

            // Get the current rock version
            var rockVersion = new Version(Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber());

            // put the migrations to run in a Dictionary so that we can run them in the correct order
            // based on MigrationNumberAttribute
            var migrationTypesByNumber = new Dictionary <int, Type>();

            // Iterate plugin migrations
            foreach (var migrationType in pluginMigrationTypes)
            {
                // Get the MigrationNumberAttribute for the migration
                var migrationNumberAttr = migrationType.GetCustomAttribute <Rock.Plugin.MigrationNumberAttribute>();
                if (migrationNumberAttr != null)
                {
                    // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                    var minRockVersion = new Version(migrationNumberAttr.MinimumRockVersion);
                    if (minRockVersion.CompareTo(rockVersion) <= 0)
                    {
                        // Check to make sure no another migration has same number
                        if (migrationTypesByNumber.ContainsKey(migrationNumberAttr.Number))
                        {
                            throw new RockStartupException($"The '{pluginAssemblyName}' plugin assembly contains duplicate migration numbers ({ migrationNumberAttr.Number}).");
                        }

                        migrationTypesByNumber.Add(migrationNumberAttr.Number, migrationType);
                    }
                }
            }

            // Create EF service for plugin migrations
            var rockContext            = new RockContext();
            var pluginMigrationService = new PluginMigrationService(rockContext);

            // Get the versions that have already been installed
            var installedMigrationNumbers = pluginMigrationService.Queryable()
                                            .Where(m => m.PluginAssemblyName == pluginAssemblyName)
                                            .Select(a => a.MigrationNumber);

            // narrow it down to migrations that haven't already been installed
            migrationTypesByNumber = migrationTypesByNumber
                                     .Where(a => !installedMigrationNumbers.Contains(a.Key))
                                     .ToDictionary(k => k.Key, v => v.Value);

            // Iterate each migration in the assembly in MigrationNumber order
            var migrationTypesToRun = migrationTypesByNumber.OrderBy(a => a.Key).Select(a => a.Value).ToList();

            var configConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["RockContext"]?.ConnectionString;

            try
            {
                using (var sqlConnection = new SqlConnection(configConnectionString))
                {
                    try
                    {
                        sqlConnection.Open();
                    }
                    catch (SqlException ex)
                    {
                        throw new RockStartupException("Error connecting to the SQL database. Please check the 'RockContext' connection string in the web.ConnectionString.config file.", ex);
                    }

                    // Iterate thru each plugin migration in this assembly, if one fails, will log the exception and stop running migrations for this assembly
                    foreach (Type migrationType in migrationTypesToRun)
                    {
                        int migrationNumber = migrationType.GetCustomAttribute <Rock.Plugin.MigrationNumberAttribute>().Number;

                        using (var sqlTxn = sqlConnection.BeginTransaction())
                        {
                            bool transactionActive = true;
                            try
                            {
                                // Create an instance of the migration and run the up migration
                                var migration = Activator.CreateInstance(migrationType) as Rock.Plugin.Migration;
                                migration.SqlConnection  = sqlConnection;
                                migration.SqlTransaction = sqlTxn;
                                migration.Up();
                                sqlTxn.Commit();
                                transactionActive = false;

                                // Save the plugin migration version so that it is not run again
                                var pluginMigration = new PluginMigration();
                                pluginMigration.PluginAssemblyName = pluginAssemblyName;
                                pluginMigration.MigrationNumber    = migrationNumber;
                                pluginMigration.MigrationName      = migrationType.Name;
                                pluginMigrationService.Add(pluginMigration);
                                rockContext.SaveChanges();

                                result = true;
                            }
                            catch (Exception ex)
                            {
                                if (transactionActive)
                                {
                                    sqlTxn.Rollback();
                                }

                                throw new RockStartupException($"##Plugin Migration error occurred in { migrationNumber}, {migrationType.Name}##", ex);
                            }
                        }
                    }
                }
            }
            catch (RockStartupException rockStartupException)
            {
                // if a plugin migration got an error, it gets wrapped with a RockStartupException
                // If this occurs, we'll log the migration that occurred,  and stop running migrations for this assembly
                System.Diagnostics.Debug.WriteLine(rockStartupException.Message);
                LogError(rockStartupException, null);
            }
            catch (Exception ex)
            {
                // If an exception occurs in an an assembly, log the error, and stop running migrations for this assembly
                var startupException = new RockStartupException($"Error running migrations from {pluginAssemblyName}");
                System.Diagnostics.Debug.WriteLine(startupException.Message);
                LogError(ex, null);
            }

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// Migrates the plugins.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">
        /// Could not connect to the SQL database! Please check the 'RockContext' connection string in the web.ConnectionString.config file.
        /// or
        /// </exception>
        public bool MigratePlugins(RockContext rockContext)
        {
            bool result = false;

            // Migrate any plugins that have pending migrations
            List <Type> migrationList = Rock.Reflection.FindTypes(typeof(Migration)).Select(a => a.Value).ToList();

            // If any plugin migrations types were found
            if (migrationList.Any())
            {
                // Create EF service for plugin migrations
                var pluginMigrationService = new PluginMigrationService(rockContext);

                // Get the current rock version
                var rockVersion = new Version(Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber());

                // Create dictionary for holding migrations specific to an assembly
                var assemblies = new Dictionary <string, Dictionary <int, Type> >();

                // Iterate plugin migrations
                foreach (var migrationType in migrationList)
                {
                    // Get the MigrationNumberAttribute for the migration
                    var migrationNumberAttr = System.Attribute.GetCustomAttribute(migrationType, typeof(MigrationNumberAttribute)) as MigrationNumberAttribute;
                    if (migrationNumberAttr != null)
                    {
                        // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                        var minRockVersion = new Version(migrationNumberAttr.MinimumRockVersion);
                        if (minRockVersion.CompareTo(rockVersion) <= 0)
                        {
                            string assemblyName = migrationType.Assembly.GetName().Name;
                            if (!assemblies.ContainsKey(assemblyName))
                            {
                                assemblies.Add(assemblyName, new Dictionary <int, Type>());
                            }

                            // Check to make sure no another migration has same number
                            if (assemblies[assemblyName].ContainsKey(migrationNumberAttr.Number))
                            {
                                throw new Exception(string.Format("The '{0}' plugin assembly contains duplicate migration numbers ({1}).", assemblyName, migrationNumberAttr.Number));
                            }
                            assemblies[assemblyName].Add(migrationNumberAttr.Number, migrationType);
                        }
                    }
                }

                var configConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["RockContext"];
                if (configConnectionString != null)
                {
                    string connectionString = configConnectionString.ConnectionString;
                    if (!string.IsNullOrWhiteSpace(connectionString))
                    {
                        using (SqlConnection con = new SqlConnection(connectionString))
                        {
                            try
                            {
                                con.Open();
                            }
                            catch (SqlException ex)
                            {
                                throw new Exception("Could not connect to the SQL database! Please check the 'RockContext' connection string in the web.ConnectionString.config file.", ex);
                            }

                            // Iterate each assembly that contains plugin migrations
                            foreach (var assemblyMigrations in assemblies)
                            {
                                try
                                {
                                    // Get the versions that have already been installed
                                    var installedVersions = pluginMigrationService.Queryable()
                                                            .Where(m => m.PluginAssemblyName == assemblyMigrations.Key)
                                                            .ToList();

                                    // Iterate each migration in the assembly in MigrationNumber order
                                    foreach (var migrationType in assemblyMigrations.Value.OrderBy(t => t.Key))
                                    {
                                        // Check to make sure migration has not already been run
                                        if (!installedVersions.Any(v => v.MigrationNumber == migrationType.Key))
                                        {
                                            using (var sqlTxn = con.BeginTransaction())
                                            {
                                                bool transactionActive = true;
                                                try
                                                {
                                                    // Create an instance of the migration and run the up migration
                                                    var migration = Activator.CreateInstance(migrationType.Value) as Rock.Plugin.Migration;
                                                    migration.SqlConnection  = con;
                                                    migration.SqlTransaction = sqlTxn;
                                                    migration.Up();
                                                    sqlTxn.Commit();
                                                    transactionActive = false;

                                                    // Save the plugin migration version so that it is not run again
                                                    var pluginMigration = new PluginMigration();
                                                    pluginMigration.PluginAssemblyName = assemblyMigrations.Key;
                                                    pluginMigration.MigrationNumber    = migrationType.Key;
                                                    pluginMigration.MigrationName      = migrationType.Value.Name;
                                                    pluginMigrationService.Add(pluginMigration);
                                                    rockContext.SaveChanges();

                                                    result = true;
                                                }
                                                catch (Exception ex)
                                                {
                                                    if (transactionActive)
                                                    {
                                                        sqlTxn.Rollback();
                                                    }
                                                    throw new Exception(string.Format("Plugin Migration error occurred in {0}, {1}",
                                                                                      assemblyMigrations.Key, migrationType.Value.Name), ex);
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // If an exception occurs in an an assembly, log the error, and continue with next assembly
                                    LogError(ex, null);
                                }
                            }
                        }
                    }
                }
            }

            return(result);
        }
Esempio n. 3
0
        /// <summary>
        /// Migrates the database.
        /// </summary>
        /// <returns>True if at least one migration was run</returns>
        public bool MigrateDatabase( RockContext rockContext )
        {
            bool result = false;

            var fileInfo = new FileInfo( Server.MapPath( "~/App_Data/Run.Migration" ) );
            if ( fileInfo.Exists )
            {
                Database.SetInitializer( new MigrateDatabaseToLatestVersion<Rock.Data.RockContext, Rock.Migrations.Configuration>() );

                // explictly check if the database exists, and force create it if doesn't exist
                if ( !rockContext.Database.Exists() )
                {
                    // If database did not exist, initialize a database (which runs existing Rock migrations)
                    rockContext.Database.Initialize( true );
                    result = true;
                }
                else
                {
                    // If database does exist, run any pending Rock migrations
                    var migrator = new System.Data.Entity.Migrations.DbMigrator( new Rock.Migrations.Configuration() );
                    if ( migrator.GetPendingMigrations().Any() )
                    {
                        migrator.Update();
                        result = true;
                    }
                }

                fileInfo.Delete();
            }
            else
            {
                // default Initializer is CreateDatabaseIfNotExists, but we don't want that to happen if automigrate is false, so set it to NULL so that nothing happens
                Database.SetInitializer<Rock.Data.RockContext>( null );
            }

            // Migrate any plugins that have pending migrations
            List<Type> migrationList = Rock.Reflection.FindTypes( typeof( Migration ) ).Select( a => a.Value ).ToList();

            // If any plugin migrations types were found
            if ( migrationList.Any() )
            {
                // Create EF service for plugin migrations
                var pluginMigrationService = new PluginMigrationService( rockContext );

                // Get the current rock version
                var rockVersion = new Version( Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber() );

                // Create dictionary for holding migrations specific to an assembly
                var assemblies = new Dictionary<string, Dictionary<int, Type>>();

                // Iterate plugin migrations
                foreach ( var migrationType in migrationList )
                {
                    // Get the MigrationNumberAttribute for the migration
                    var migrationNumberAttr = System.Attribute.GetCustomAttribute( migrationType, typeof( MigrationNumberAttribute ) ) as MigrationNumberAttribute;
                    if ( migrationNumberAttr != null )
                    {
                        // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                        var minRockVersion = new Version( migrationNumberAttr.MinimumRockVersion );
                        if ( minRockVersion.CompareTo( rockVersion ) <= 0 )
                        {
                            string assemblyName = migrationType.Assembly.GetName().Name;
                            if ( !assemblies.ContainsKey( assemblyName ) )
                            {
                                assemblies.Add( assemblyName, new Dictionary<int, Type>() );
                            }
                            assemblies[assemblyName].Add( migrationNumberAttr.Number, migrationType );
                        }
                    }
                }

                var configConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["RockContext"];
                if ( configConnectionString != null )
                {
                    string connectionString = configConnectionString.ConnectionString;
                    if ( !string.IsNullOrWhiteSpace( connectionString ) )
                    {
                        using ( SqlConnection con = new SqlConnection( connectionString ) )
                        {
                            con.Open();

                            // Iterate each assembly that contains plugin migrations
                            foreach ( var assemblyMigrations in assemblies )
                            {
                                try
                                {
                                    // Get the versions that have already been installed
                                    var installedVersions = pluginMigrationService.Queryable()
                                        .Where( m => m.PluginAssemblyName == assemblyMigrations.Key )
                                        .ToList();

                                    // Iterate each migration in the assembly in MigrationNumber order
                                    foreach ( var migrationType in assemblyMigrations.Value.OrderBy( t => t.Key ) )
                                    {
                                        // Check to make sure migration has not already been run
                                        if ( !installedVersions.Any( v => v.MigrationNumber == migrationType.Key ) )
                                        {
                                            using ( var sqlTxn = con.BeginTransaction() )
                                            {
                                                bool transactionActive = true;
                                                try
                                                {
                                                    // Create an instance of the migration and run the up migration
                                                    var migration = Activator.CreateInstance( migrationType.Value ) as Rock.Plugin.Migration;
                                                    migration.SqlConnection = con;
                                                    migration.SqlTransaction = sqlTxn;
                                                    migration.Up();
                                                    sqlTxn.Commit();
                                                    transactionActive = false;

                                                    // Save the plugin migration version so that it is not run again
                                                    var pluginMigration = new PluginMigration();
                                                    pluginMigration.PluginAssemblyName = assemblyMigrations.Key;
                                                    pluginMigration.MigrationNumber = migrationType.Key;
                                                    pluginMigration.MigrationName = migrationType.Value.Name;
                                                    pluginMigrationService.Add( pluginMigration );
                                                    rockContext.SaveChanges();

                                                    result = true;
                                                }
                                                catch ( Exception ex )
                                                {
                                                    if ( transactionActive )
                                                    {
                                                        sqlTxn.Rollback();
                                                    }
                                                    throw new Exception( string.Format( "Plugin Migration error occurred in {0}, {1}",
                                                        assemblyMigrations.Key, migrationType.Value.Name ), ex );
                                                }
                                            }
                                        }
                                    }
                                }
                                catch ( Exception ex )
                                {
                                    // If an exception occurs in an an assembly, log the error, and continue with next assembly
                                    LogError( ex, null );
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }
        /// <summary>
        /// Migrates the plugins.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        /// <exception cref="System.Exception">
        /// Could not connect to the SQL database! Please check the 'RockContext' connection string in the web.ConnectionString.config file.
        /// or
        /// </exception>
        public bool MigratePlugins( RockContext rockContext )
        {
            bool result = false;

            // Migrate any plugins that have pending migrations
            List<Type> migrationList = Rock.Reflection.FindTypes( typeof( Migration ) ).Select( a => a.Value ).ToList();

            // If any plugin migrations types were found
            if ( migrationList.Any() )
            {
                // Create EF service for plugin migrations
                var pluginMigrationService = new PluginMigrationService( rockContext );

                // Get the current rock version
                var rockVersion = new Version( Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber() );

                // Create dictionary for holding migrations specific to an assembly
                var assemblies = new Dictionary<string, Dictionary<int, Type>>();

                // Iterate plugin migrations
                foreach ( var migrationType in migrationList )
                {
                    // Get the MigrationNumberAttribute for the migration
                    var migrationNumberAttr = System.Attribute.GetCustomAttribute( migrationType, typeof( MigrationNumberAttribute ) ) as MigrationNumberAttribute;
                    if ( migrationNumberAttr != null )
                    {
                        // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                        var minRockVersion = new Version( migrationNumberAttr.MinimumRockVersion );
                        if ( minRockVersion.CompareTo( rockVersion ) <= 0 )
                        {
                            string assemblyName = migrationType.Assembly.GetName().Name;
                            if ( !assemblies.ContainsKey( assemblyName ) )
                            {
                                assemblies.Add( assemblyName, new Dictionary<int, Type>() );
                            }
                            assemblies[assemblyName].Add( migrationNumberAttr.Number, migrationType );
                        }
                    }
                }

                var configConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["RockContext"];
                if ( configConnectionString != null )
                {
                    string connectionString = configConnectionString.ConnectionString;
                    if ( !string.IsNullOrWhiteSpace( connectionString ) )
                    {
                        using ( SqlConnection con = new SqlConnection( connectionString ) )
                        {
                            try
                            {
                                con.Open();
                            }
                            catch ( SqlException ex )
                            {
                                throw new Exception( "Could not connect to the SQL database! Please check the 'RockContext' connection string in the web.ConnectionString.config file.", ex );
                            }

                            // Iterate each assembly that contains plugin migrations
                            foreach ( var assemblyMigrations in assemblies )
                            {
                                try
                                {
                                    // Get the versions that have already been installed
                                    var installedVersions = pluginMigrationService.Queryable()
                                        .Where( m => m.PluginAssemblyName == assemblyMigrations.Key )
                                        .ToList();

                                    // Iterate each migration in the assembly in MigrationNumber order
                                    foreach ( var migrationType in assemblyMigrations.Value.OrderBy( t => t.Key ) )
                                    {
                                        // Check to make sure migration has not already been run
                                        if ( !installedVersions.Any( v => v.MigrationNumber == migrationType.Key ) )
                                        {
                                            using ( var sqlTxn = con.BeginTransaction() )
                                            {
                                                bool transactionActive = true;
                                                try
                                                {
                                                    // Create an instance of the migration and run the up migration
                                                    var migration = Activator.CreateInstance( migrationType.Value ) as Rock.Plugin.Migration;
                                                    migration.SqlConnection = con;
                                                    migration.SqlTransaction = sqlTxn;
                                                    migration.Up();
                                                    sqlTxn.Commit();
                                                    transactionActive = false;

                                                    // Save the plugin migration version so that it is not run again
                                                    var pluginMigration = new PluginMigration();
                                                    pluginMigration.PluginAssemblyName = assemblyMigrations.Key;
                                                    pluginMigration.MigrationNumber = migrationType.Key;
                                                    pluginMigration.MigrationName = migrationType.Value.Name;
                                                    pluginMigrationService.Add( pluginMigration );
                                                    rockContext.SaveChanges();

                                                    result = true;
                                                }
                                                catch ( Exception ex )
                                                {
                                                    if ( transactionActive )
                                                    {
                                                        sqlTxn.Rollback();
                                                    }
                                                    throw new Exception( string.Format( "Plugin Migration error occurred in {0}, {1}",
                                                        assemblyMigrations.Key, migrationType.Value.Name ), ex );
                                                }
                                            }
                                        }
                                    }
                                }
                                catch ( Exception ex )
                                {
                                    // If an exception occurs in an an assembly, log the error, and continue with next assembly
                                    LogError( ex, null );
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }
Esempio n. 5
0
        /// <summary>
        /// Migrates the database.
        /// </summary>
        public void MigrateDatabase()
        {
            // Check if database should be auto-migrated for the core and plugins
            if ( ConfigurationManager.AppSettings["AutoMigrateDatabase"].AsBoolean( true ) )
            {
                try
                {
                    Database.SetInitializer( new MigrateDatabaseToLatestVersion<Rock.Data.RockContext, Rock.Migrations.Configuration>() );

                    var rockContext = new RockContext();

                    // explictly check if the database exists, and force create it if doesn't exist
                    if ( !rockContext.Database.Exists() )
                    {
                        // If database did not exist, initialize a database (which runs existing Rock migrations)
                        rockContext.Database.Initialize( true );
                    }
                    else
                    {
                        // If database does exist, run any pending Rock migrations
                        var migrator = new System.Data.Entity.Migrations.DbMigrator( new Rock.Migrations.Configuration() );
                        migrator.Update();
                    }

                    // Migrate any plugins that have pending migrations
                    List<Type> migrationList = Rock.Reflection.FindTypes( typeof( Migration ) ).Select( a => a.Value ).ToList();

                    // If any plugin migrations types were found
                    if ( migrationList.Any() )
                    {
                        // Create EF service for plugin migrations
                        var pluginMigrationService = new PluginMigrationService( rockContext );

                        // Get the current rock version
                        var rockVersion = new Version( Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber() );

                        // Create dictionary for holding migrations specific to an assembly
                        var assemblies = new Dictionary<string, Dictionary<int, Type>>();

                        // Iterate plugin migrations
                        foreach ( var migrationType in migrationList )
                        {
                            // Get the MigrationNumberAttribute for the migration
                            var migrationNumberAttr = System.Attribute.GetCustomAttribute( migrationType, typeof( MigrationNumberAttribute ) ) as MigrationNumberAttribute;
                            if ( migrationNumberAttr != null )
                            {
                                // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                                var minRockVersion = new Version( migrationNumberAttr.MinimumRockVersion );
                                if ( minRockVersion.CompareTo( rockVersion ) <= 0 )
                                {
                                    string assemblyName = migrationType.Assembly.GetName().Name;
                                    if ( !assemblies.ContainsKey( assemblyName ) )
                                    {
                                        assemblies.Add( assemblyName, new Dictionary<int, Type>() );
                                    }
                                    assemblies[assemblyName].Add( migrationNumberAttr.Number, migrationType );
                                }
                            }
                        }

                        // Iterate each assembly that contains plugin migrations
                        foreach ( var assemblyMigrations in assemblies )
                        {
                            try
                            {
                                // Get the versions that have already been installed
                                var installedVersions = pluginMigrationService.Queryable()
                                    .Where( m => m.PluginAssemblyName == assemblyMigrations.Key )
                                    .ToList();

                                // Wrap the migrations for each assembly in a transaction so that if an error with one migration, none of the migrations are persisted
                                RockTransactionScope.WrapTransaction( () =>
                                {
                                    // Iterate each migration in the assembly in MigrationNumber order
                                    foreach ( var migrationType in assemblyMigrations.Value.OrderBy( t => t.Key ) )
                                    {
                                        // Check to make sure migration has not already been run
                                        if ( !installedVersions.Any( v => v.MigrationNumber == migrationType.Key ) )
                                        {
                                            try
                                            {
                                                // Create an instance of the migration and run the up migration
                                                var migration = Activator.CreateInstance( migrationType.Value ) as Rock.Plugin.Migration;
                                                migration.Up();

                                                // Save the plugin migration version so that it is not run again
                                                var pluginMigration = new PluginMigration();
                                                pluginMigration.PluginAssemblyName = assemblyMigrations.Key;
                                                pluginMigration.MigrationNumber = migrationType.Key;
                                                pluginMigration.MigrationName = migrationType.Value.Name;
                                                pluginMigrationService.Add( pluginMigration );
                                                rockContext.SaveChanges();
                                            }
                                            catch ( Exception ex )
                                            {
                                                throw new Exception( string.Format( "Plugin Migration error occurred in {0}, {1}",
                                                    assemblyMigrations.Key, migrationType.Value.Name ), ex );
                                            }
                                        }
                                    }
                                } );
                            }
                            catch ( Exception ex )
                            {
                                // If an exception occurs in an an assembly, log the error, and continue with next assembly
                                LogError( ex, null );
                            }
                        }
                    }
                }
                catch ( Exception ex )
                {
                    // if migrations fail, log error and attempt to continue
                    LogError( ex, null );
                }

            }
            else
            {
                // default Initializer is CreateDatabaseIfNotExists, but we don't want that to happen if automigrate is false, so set it to NULL so that nothing happens
                Database.SetInitializer<Rock.Data.RockContext>( null );
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Migrates the database.
        /// </summary>
        public void MigrateDatabase()
        {
            // Check if database should be auto-migrated for the core and plugins
            if (ConfigurationManager.AppSettings["AutoMigrateDatabase"].AsBoolean(true))
            {
                try
                {
                    Database.SetInitializer(new MigrateDatabaseToLatestVersion <Rock.Data.RockContext, Rock.Migrations.Configuration>());

                    var rockContext = new RockContext();

                    // explictly check if the database exists, and force create it if doesn't exist
                    if (!rockContext.Database.Exists())
                    {
                        // If database did not exist, initialize a database (which runs existing Rock migrations)
                        rockContext.Database.Initialize(true);
                    }
                    else
                    {
                        // If database does exist, run any pending Rock migrations
                        var migrator = new System.Data.Entity.Migrations.DbMigrator(new Rock.Migrations.Configuration());
                        migrator.Update();
                    }

                    // Migrate any plugins that have pending migrations
                    List <Type> migrationList = Rock.Reflection.FindTypes(typeof(Migration)).Select(a => a.Value).ToList();

                    // If any plugin migrations types were found
                    if (migrationList.Any())
                    {
                        // Create EF service for plugin migrations
                        var pluginMigrationService = new PluginMigrationService(rockContext);

                        // Get the current rock version
                        var rockVersion = new Version(Rock.VersionInfo.VersionInfo.GetRockProductVersionNumber());

                        // Create dictionary for holding migrations specific to an assembly
                        var assemblies = new Dictionary <string, Dictionary <int, Type> >();

                        // Iterate plugin migrations
                        foreach (var migrationType in migrationList)
                        {
                            // Get the MigrationNumberAttribute for the migration
                            var migrationNumberAttr = System.Attribute.GetCustomAttribute(migrationType, typeof(MigrationNumberAttribute)) as MigrationNumberAttribute;
                            if (migrationNumberAttr != null)
                            {
                                // If the migration's minimum Rock version is less than or equal to the current rock version, add it to the list
                                var minRockVersion = new Version(migrationNumberAttr.MinimumRockVersion);
                                if (minRockVersion.CompareTo(rockVersion) <= 0)
                                {
                                    string assemblyName = migrationType.Assembly.GetName().Name;
                                    if (!assemblies.ContainsKey(assemblyName))
                                    {
                                        assemblies.Add(assemblyName, new Dictionary <int, Type>());
                                    }
                                    assemblies[assemblyName].Add(migrationNumberAttr.Number, migrationType);
                                }
                            }
                        }

                        // Iterate each assembly that contains plugin migrations
                        foreach (var assemblyMigrations in assemblies)
                        {
                            try
                            {
                                // Get the versions that have already been installed
                                var installedVersions = pluginMigrationService.Queryable()
                                                        .Where(m => m.PluginAssemblyName == assemblyMigrations.Key)
                                                        .ToList();

                                // Wrap the migrations for each assembly in a transaction so that if an error with one migration, none of the migrations are persisted
                                RockTransactionScope.WrapTransaction(() =>
                                {
                                    // Iterate each migration in the assembly in MigrationNumber order
                                    foreach (var migrationType in assemblyMigrations.Value.OrderBy(t => t.Key))
                                    {
                                        // Check to make sure migration has not already been run
                                        if (!installedVersions.Any(v => v.MigrationNumber == migrationType.Key))
                                        {
                                            try
                                            {
                                                // Create an instance of the migration and run the up migration
                                                var migration = Activator.CreateInstance(migrationType.Value) as Rock.Plugin.Migration;
                                                migration.Up();

                                                // Save the plugin migration version so that it is not run again
                                                var pluginMigration = new PluginMigration();
                                                pluginMigration.PluginAssemblyName = assemblyMigrations.Key;
                                                pluginMigration.MigrationNumber    = migrationType.Key;
                                                pluginMigration.MigrationName      = migrationType.Value.Name;
                                                pluginMigrationService.Add(pluginMigration);
                                                rockContext.SaveChanges();
                                            }
                                            catch (Exception ex)
                                            {
                                                throw new Exception(string.Format("Plugin Migration error occurred in {0}, {1}",
                                                                                  assemblyMigrations.Key, migrationType.Value.Name), ex);
                                            }
                                        }
                                    }
                                });
                            }
                            catch (Exception ex)
                            {
                                // If an exception occurs in an an assembly, log the error, and continue with next assembly
                                LogError(ex, null);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // if migrations fail, log error and attempt to continue
                    LogError(ex, null);
                }
            }
            else
            {
                // default Initializer is CreateDatabaseIfNotExists, but we don't want that to happen if automigrate is false, so set it to NULL so that nothing happens
                Database.SetInitializer <Rock.Data.RockContext>(null);
            }
        }