entity-framework-coreentity-framework-core-migrations

dotnet ef migrations add: create migration file only if there are changes


I'm using dotnet ef migrations add {MigrationName} in order to create a new migration.

In case there are no Entities/Context changes this creates a migration with empty Up(MigrationBuilder migrationBuilder) and Down(MigrationBuilder migrationBuilder) functions.

Is there a way for the migrations add command to skip the creation of 'empty' files?

Alternatively, Is there a way to detect if there are changes before running the migrations add command?


Solution

  • I found a solution to this problem.

    There is a way to create migrations programmatically instead of using CLI.

    After looking at the MigrationsScaffolder source code I managed to modify the code in the first link in order to support my needs:

            using (var db = new MyDbContext())
            {
                var reporter = new OperationReporter(
                    new OperationReportHandler(
                        m => Console.WriteLine("  error: " + m),
                        m => Console.WriteLine("   warn: " + m),
                        m => Console.WriteLine("   info: " + m),
                        m => Console.WriteLine("verbose: " + m)));
    
                var designTimeServices = new ServiceCollection()
                    .AddSingleton(db.GetService<IHistoryRepository>())
                    .AddSingleton(db.GetService<IMigrationsIdGenerator>())
                    .AddSingleton(db.GetService<IMigrationsModelDiffer>())
                    .AddSingleton(db.GetService<IMigrationsAssembly>())
                    .AddSingleton(db.Model)
                    .AddSingleton(db.GetService<ICurrentDbContext>())
                    .AddSingleton(db.GetService<IDatabaseProvider>())
                    .AddSingleton<MigrationsCodeGeneratorDependencies>()
                    .AddSingleton<ICSharpHelper, CSharpHelper>()
                    .AddSingleton<CSharpMigrationOperationGeneratorDependencies>()
                    .AddSingleton<ICSharpMigrationOperationGenerator, CSharpMigrationOperationGenerator>()
                    .AddSingleton<CSharpSnapshotGeneratorDependencies>()
                    .AddSingleton<ICSharpSnapshotGenerator, CSharpSnapshotGenerator>()
                    .AddSingleton<CSharpMigrationsGeneratorDependencies>()
                    .AddSingleton<IMigrationsCodeGenerator, CSharpMigrationsGenerator>()
                    .AddSingleton<IOperationReporter>(reporter)
                    .AddSingleton<MigrationsScaffolderDependencies>()
                    .AddSingleton<ISnapshotModelProcessor, SnapshotModelProcessor>()
                    .AddSingleton<MigrationsScaffolder>()
                    .BuildServiceProvider();
    
                var scaffolderDependencies = designTimeServices.GetRequiredService<MigrationsScaffolderDependencies>();
    
                var modelSnapshot = scaffolderDependencies.MigrationsAssembly.ModelSnapshot;
                var lastModel = scaffolderDependencies.SnapshotModelProcessor.Process(modelSnapshot?.Model);
                var upOperations = scaffolderDependencies.MigrationsModelDiffer.GetDifferences(lastModel, scaffolderDependencies.Model);
                var downOperations = upOperations.Any() ? scaffolderDependencies.MigrationsModelDiffer.GetDifferences(scaffolderDependencies.Model, lastModel) : new List<MigrationOperation>();
    
                if (upOperations.Count() > 0 || downOperations.Count() > 0)
                {
                    var scaffolder = designTimeServices.GetRequiredService<MigrationsScaffolder>();
    
                    var migration = scaffolder.ScaffoldMigration(
                        "MyMigration",
                        "MyApp.Data");
    
                    File.WriteAllText(
                        migration.MigrationId + migration.FileExtension,
                        migration.MigrationCode);
                    File.WriteAllText(
                        migration.MigrationId + ".Designer" + migration.FileExtension,
                        migration.MetadataCode);
                    File.WriteAllText(migration.SnapshotName + migration.FileExtension,
                       migration.SnapshotCode);
                }
            }