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); }