/// <summary> /// Removes the previous migration. /// </summary> /// <param name="projectDir"> The project's root directory. </param> /// <param name="rootNamespace"> The project's root namespace. </param> /// <param name="force"> Don't check to see if the migration has been applied to the database. </param> /// <param name="language"> The project's language. </param> /// <returns> The removed migration files. </returns> // TODO: DRY (file names) public virtual MigrationFiles RemoveMigration( string projectDir, string rootNamespace, bool force, string language) { Check.NotEmpty(projectDir, nameof(projectDir)); Check.NotEmpty(rootNamespace, nameof(rootNamespace)); var files = new MigrationFiles(); var modelSnapshot = Dependencies.MigrationsAssembly.ModelSnapshot; if (modelSnapshot == null) { throw new OperationException(DesignStrings.NoSnapshot); } var codeGenerator = Dependencies.MigrationsCodeGeneratorSelector.Select(language); IModel model = null; var migrations = Dependencies.MigrationsAssembly.Migrations .Select(m => Dependencies.MigrationsAssembly.CreateMigration(m.Value, _activeProvider)) .ToList(); if (migrations.Count != 0) { var migration = migrations[migrations.Count - 1]; model = migration.TargetModel; if (!Dependencies.MigrationsModelDiffer.HasDifferences( model.GetRelationalModel(), Dependencies.SnapshotModelProcessor.Process(modelSnapshot.Model).GetRelationalModel())) { var applied = false; try { applied = Dependencies.HistoryRepository.GetAppliedMigrations().Any( e => e.MigrationId.Equals(migration.GetId(), StringComparison.OrdinalIgnoreCase)); } catch (Exception ex) when(force) { Dependencies.OperationReporter.WriteVerbose(ex.ToString()); Dependencies.OperationReporter.WriteWarning( DesignStrings.ForceRemoveMigration(migration.GetId(), ex.Message)); } if (applied) { if (force) { Dependencies.Migrator.Migrate( migrations.Count > 1 ? migrations[migrations.Count - 2].GetId() : Migration.InitialDatabase); } else { throw new OperationException(DesignStrings.RevertMigration(migration.GetId())); } } var migrationFileName = migration.GetId() + codeGenerator.FileExtension; var migrationFile = TryGetProjectFile(projectDir, migrationFileName); if (migrationFile != null) { Dependencies.OperationReporter.WriteInformation(DesignStrings.RemovingMigration(migration.GetId())); File.Delete(migrationFile); files.MigrationFile = migrationFile; } else { Dependencies.OperationReporter.WriteWarning( DesignStrings.NoMigrationFile(migrationFileName, migration.GetType().ShortDisplayName())); } var migrationMetadataFileName = migration.GetId() + ".Designer" + codeGenerator.FileExtension; var migrationMetadataFile = TryGetProjectFile(projectDir, migrationMetadataFileName); if (migrationMetadataFile != null) { File.Delete(migrationMetadataFile); files.MetadataFile = migrationMetadataFile; } else { Dependencies.OperationReporter.WriteVerbose( DesignStrings.NoMigrationMetadataFile(migrationMetadataFile)); } model = migrations.Count > 1 ? migrations[migrations.Count - 2].TargetModel : null; } else { Dependencies.OperationReporter.WriteVerbose(DesignStrings.ManuallyDeleted); } } var modelSnapshotName = modelSnapshot.GetType().Name; var modelSnapshotFileName = modelSnapshotName + codeGenerator.FileExtension; var modelSnapshotFile = TryGetProjectFile(projectDir, modelSnapshotFileName); if (model == null) { if (modelSnapshotFile != null) { Dependencies.OperationReporter.WriteInformation(DesignStrings.RemovingSnapshot); File.Delete(modelSnapshotFile); files.SnapshotFile = modelSnapshotFile; } else { Dependencies.OperationReporter.WriteWarning( DesignStrings.NoSnapshotFile( modelSnapshotFileName, modelSnapshot.GetType().ShortDisplayName())); } } else { var modelSnapshotNamespace = modelSnapshot.GetType().Namespace; Check.DebugAssert(!string.IsNullOrEmpty(modelSnapshotNamespace), "modelSnapshotNamespace is null or empty"); var modelSnapshotCode = codeGenerator.GenerateSnapshot( modelSnapshotNamespace, _contextType, modelSnapshotName, model); if (modelSnapshotFile == null) { modelSnapshotFile = Path.Combine( GetDirectory(projectDir, null, GetSubNamespace(rootNamespace, modelSnapshotNamespace)), modelSnapshotFileName); } Dependencies.OperationReporter.WriteInformation(DesignStrings.RevertingSnapshot); File.WriteAllText(modelSnapshotFile, modelSnapshotCode, Encoding.UTF8); } return(files); }
// TODO: DRY (file names) public virtual MigrationFiles RemoveMigration([NotNull] string projectDir, [NotNull] string rootNamespace, bool force) { Check.NotEmpty(projectDir, nameof(projectDir)); Check.NotEmpty(rootNamespace, nameof(rootNamespace)); var files = new MigrationFiles(); var modelSnapshot = _migrationsAssembly.ModelSnapshot; if (modelSnapshot == null) { throw new OperationException(DesignStrings.NoSnapshot); } var language = _migrationCodeGenerator.FileExtension; IModel model = null; var migrations = _migrationsAssembly.Migrations .Select(m => _migrationsAssembly.CreateMigration(m.Value, _activeProvider)) .ToList(); if (migrations.Count != 0) { var migration = migrations[migrations.Count - 1]; model = migration.TargetModel; if (!_modelDiffer.HasDifferences(model, modelSnapshot.Model)) { if (force) { _logger.LogWarning( DesignEventId.ForceRemoveMigration, () => DesignStrings.ForceRemoveMigration(migration.GetId())); } else if (_historyRepository.GetAppliedMigrations().Any( e => e.MigrationId.Equals(migration.GetId(), StringComparison.OrdinalIgnoreCase))) { throw new OperationException(DesignStrings.UnapplyMigration(migration.GetId())); } var migrationFileName = migration.GetId() + language; var migrationFile = TryGetProjectFile(projectDir, migrationFileName); if (migrationFile != null) { _logger.LogInformation( DesignEventId.RemovingMigration, () => DesignStrings.RemovingMigration(migration.GetId())); File.Delete(migrationFile); files.MigrationFile = migrationFile; } else { _logger.LogWarning( DesignEventId.NoMigrationFile, () => DesignStrings.NoMigrationFile(migrationFileName, migration.GetType().ShortDisplayName())); } var migrationMetadataFileName = migration.GetId() + ".Designer" + language; var migrationMetadataFile = TryGetProjectFile(projectDir, migrationMetadataFileName); if (migrationMetadataFile != null) { File.Delete(migrationMetadataFile); files.MetadataFile = migrationMetadataFile; } else { _logger.LogDebug( DesignEventId.NoMigrationMetadataFile, () => DesignStrings.NoMigrationMetadataFile(migrationMetadataFileName)); } model = migrations.Count > 1 ? migrations[migrations.Count - 2].TargetModel : null; } else { _logger.LogDebug( DesignEventId.ManuallyDeleted, () => DesignStrings.ManuallyDeleted); } } var modelSnapshotName = modelSnapshot.GetType().Name; var modelSnapshotFileName = modelSnapshotName + language; var modelSnapshotFile = TryGetProjectFile(projectDir, modelSnapshotFileName); if (model == null) { if (modelSnapshotFile != null) { _logger.LogInformation( DesignEventId.RemovingSnapshot, () => DesignStrings.RemovingSnapshot); File.Delete(modelSnapshotFile); files.SnapshotFile = modelSnapshotFile; } else { _logger.LogWarning( DesignEventId.NoSnapshotFile, () => DesignStrings.NoSnapshotFile(modelSnapshotFileName, modelSnapshot.GetType().ShortDisplayName())); } } else { var modelSnapshotNamespace = modelSnapshot.GetType().Namespace; Debug.Assert(!string.IsNullOrEmpty(modelSnapshotNamespace)); var modelSnapshotCode = _migrationCodeGenerator.GenerateSnapshot( modelSnapshotNamespace, _contextType, modelSnapshotName, model); if (modelSnapshotFile == null) { modelSnapshotFile = Path.Combine( GetDirectory(projectDir, null, GetSubNamespace(rootNamespace, modelSnapshotNamespace)), modelSnapshotFileName); } _logger.LogInformation( DesignEventId.RevertingSnapshot, () => DesignStrings.RevertingSnapshot); File.WriteAllText(modelSnapshotFile, modelSnapshotCode, Encoding.UTF8); } return(files); }