예제 #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);
            }
        }
        /// <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;

            // 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)
                    {
                        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;
                    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);

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

            return(result);
        }