Beispiel #1
0
        public static void ExecutePendingResourceMigrations(string resPath, SmartObjectContext dbContext)
        {
            Guard.ArgumentNotNull(() => dbContext);

            string headPath = Path.Combine(resPath, "head.txt");

            if (!File.Exists(headPath))
            {
                return;
            }

            string resHead = File.ReadAllText(headPath).Trim();

            if (!MigratorUtils.IsValidMigrationId(resHead))
            {
                return;
            }

            var migrator   = new DbMigrator(new MigrationsConfiguration());
            var migrations = GetPendingResourceMigrations(migrator, resHead);

            foreach (var id in migrations)
            {
                if (IsAutomaticMigration(id))
                {
                    continue;
                }

                if (!IsValidMigrationId(id))
                {
                    continue;
                }

                // Resolve and instantiate the DbMigration instance from the assembly
                var migration = CreateMigrationInstanceByMigrationId(id, migrator.Configuration);

                var provider = migration as ILocaleResourcesProvider;
                if (provider == null)
                {
                    continue;
                }

                var builder = new LocaleResourcesBuilder();
                provider.MigrateLocaleResources(builder);

                var resEntries  = builder.Build();
                var resMigrator = new LocaleResourcesMigrator(dbContext);
                resMigrator.Migrate(resEntries);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Migrates the database to the latest version
        /// </summary>
        /// <returns>The number of applied migrations</returns>
        public int RunPendingMigrations(TContext context)
        {
            var pendingMigrations = GetPendingMigrations().ToList();

            if (!pendingMigrations.Any())
            {
                return(0);
            }

            var coreSeeders             = new List <SeederEntry>();
            var externalSeeders         = new List <SeederEntry>();
            var isCoreMigration         = context is SmartObjectContext;
            var initialMigration        = this.GetDatabaseMigrations().LastOrDefault() ?? "[Initial]";
            var lastSuccessfulMigration = initialMigration;

            IDataSeeder <SmartObjectContext> coreSeeder     = null;
            IDataSeeder <TContext>           externalSeeder = null;

            int result = 0;

            _isMigrating = true;

            // Apply migrations
            foreach (var migrationId in pendingMigrations)
            {
                if (MigratorUtils.IsAutomaticMigration(migrationId))
                {
                    continue;
                }

                if (!MigratorUtils.IsValidMigrationId(migrationId))
                {
                    continue;
                }

                // Resolve and instantiate the DbMigration instance from the assembly
                var migration = MigratorUtils.CreateMigrationInstanceByMigrationId(migrationId, Configuration);

                // Seeders for the core DbContext must be run in any case
                // (e.g. for Resource or Setting updates even from external plugins)
                coreSeeder     = migration as IDataSeeder <SmartObjectContext>;
                externalSeeder = null;

                if (!isCoreMigration)
                {
                    // Context specific seeders should only be resolved
                    // when origin is external (e.g. a Plugin)
                    externalSeeder = migration as IDataSeeder <TContext>;
                }

                try
                {
                    // Call the actual Update() to execute this migration
                    Update(migrationId);
                    result++;
                }
                catch (AutomaticMigrationsDisabledException)
                {
                    if (context is SmartObjectContext)
                    {
                        _isMigrating = false;
                        throw;
                    }

                    // DbContexts in plugin assemblies tend to produce
                    // this error, but obviously without any negative side-effect.
                    // Therefore catch and forget!
                    // TODO: (MC) investigate this and implement a cleaner solution
                }
                catch (Exception ex)
                {
                    result       = 0;
                    _isMigrating = false;
                    throw new DbMigrationException(lastSuccessfulMigration, migrationId, ex.InnerException ?? ex, false);
                }

                if (coreSeeder != null)
                {
                    coreSeeders.Add(new SeederEntry {
                        DataSeeder          = coreSeeder,
                        MigrationId         = migrationId,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                if (externalSeeder != null)
                {
                    externalSeeders.Add(new SeederEntry {
                        DataSeeder          = externalSeeder,
                        MigrationId         = migrationId,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                lastSuccessfulMigration = migrationId;
            }

            // Apply core data seeders first
            SmartObjectContext coreContext = null;

            if (coreSeeders.Any())
            {
                coreContext = isCoreMigration ? context as SmartObjectContext : new SmartObjectContext();
                RunSeeders <SmartObjectContext>(coreSeeders, coreContext);
            }

            // Apply external data seeders
            RunSeeders <TContext>(externalSeeders, context);

            _isMigrating = false;

            Logger.Info("Database migration successful: {0} >> {1}".FormatInvariant(initialMigration, lastSuccessfulMigration));

            return(result);
        }
        /// <summary>
        /// Migrates the database to the latest version
        /// </summary>
        /// <returns>The number of applied migrations</returns>
        public int RunPendingMigrations(TContext context)
        {
            if (_lastSeedException != null)
            {
                // This can happen when a previous migration attempt failed with a rollback.
                //return 0;
                throw _lastSeedException;
            }

            var pendingMigrations = GetPendingMigrations().ToList();

            if (!pendingMigrations.Any())
            {
                return(0);
            }

            // There are pending migrations and the app version is 3.0.0 at least.
            // Earlier versions are totally blocked by AppUpdater.
            // We have to ensure that the initial migration - which is '201705281903241_MoreIndexes'
            // after squashing old 2.x and 1.x migrations - does not run if current head is '201705102339006_V3Final'.
            DbMigrationContext.Current.SetSuppressInitialCreate <TContext>(true);

            var coreSeeders             = new List <SeederEntry>();
            var externalSeeders         = new List <SeederEntry>();
            var isCoreMigration         = context is SmartObjectContext;
            var databaseMigrations      = this.GetDatabaseMigrations().ToArray();
            var initialMigration        = databaseMigrations.LastOrDefault() ?? "[Initial]";
            var lastSuccessfulMigration = databaseMigrations.FirstOrDefault();
            int result = 0;

            _isMigrating = true;

            // Apply migrations
            foreach (var migrationId in pendingMigrations)
            {
                if (MigratorUtils.IsAutomaticMigration(migrationId))
                {
                    continue;
                }

                if (!MigratorUtils.IsValidMigrationId(migrationId))
                {
                    continue;
                }

                // Resolve and instantiate the DbMigration instance from the assembly
                var migration = MigratorUtils.CreateMigrationInstanceByMigrationId(migrationId, Configuration);

                // Seeders for the core DbContext must be run in any case
                // (e.g. for Resource or Setting updates even from external plugins)
                var coreSeeder = migration as IDataSeeder <SmartObjectContext>;
                IDataSeeder <TContext> externalSeeder = null;

                if (!isCoreMigration)
                {
                    // Context specific seeders should only be resolved
                    // when origin is external (e.g. a Plugin)
                    externalSeeder = migration as IDataSeeder <TContext>;
                }

                try
                {
                    // Call the actual Update() to execute this migration
                    Update(migrationId);
                    result++;
                }
                catch (AutomaticMigrationsDisabledException)
                {
                    if (context is SmartObjectContext)
                    {
                        _isMigrating = false;
                        throw;
                    }

                    // DbContexts in plugin assemblies tend to produce
                    // this error, but obviously without any negative side-effect.
                    // Therefore catch and forget!
                    // TODO: (MC) investigate this and implement a cleaner solution
                }
                catch (Exception ex)
                {
                    result       = 0;
                    _isMigrating = false;
                    throw new DbMigrationException(lastSuccessfulMigration, migrationId, ex.InnerException ?? ex, false);
                }

                var migrationName = MigratorUtils.GetMigrationClassName(migrationId);

                if (coreSeeder != null)
                {
                    coreSeeders.Add(new SeederEntry
                    {
                        DataSeeder          = coreSeeder,
                        MigrationId         = migrationId,
                        MigrationName       = migrationName,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                if (externalSeeder != null)
                {
                    externalSeeders.Add(new SeederEntry
                    {
                        DataSeeder          = externalSeeder,
                        MigrationId         = migrationId,
                        MigrationName       = migrationName,
                        PreviousMigrationId = lastSuccessfulMigration,
                    });
                }

                lastSuccessfulMigration = migrationId;
                DbMigrationContext.Current.AddAppliedMigration(typeof(TContext), migrationId);
            }

            if (coreSeeders.Any())
            {
                // Apply core data seeders first
                var coreContext = isCoreMigration ? context as SmartObjectContext : new SmartObjectContext();
                RunSeeders <SmartObjectContext>(coreSeeders, coreContext);
            }

            // Apply external data seeders
            RunSeeders <TContext>(externalSeeders, context);

            _isMigrating = false;

            Logger.Info("Database migration successful: {0} >> {1}".FormatInvariant(initialMigration, lastSuccessfulMigration));

            return(result);
        }