Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatic Scaffold-Migration Issue After Updating to 9.0.0 #35146

Open
oONoobMasterOo opened this issue Nov 19, 2024 · 14 comments · May be fixed by #35432
Open

Programmatic Scaffold-Migration Issue After Updating to 9.0.0 #35146

oONoobMasterOo opened this issue Nov 19, 2024 · 14 comments · May be fixed by #35432
Labels
area-migrations closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression type-bug
Milestone

Comments

@oONoobMasterOo
Copy link

After updating Npgsql to version 9.0.0, I encounter the following exception while attempting to scaffold migrations programmatically:

System.InvalidOperationException: Metadata changes are not allowed when the model has been marked as read-only.
   at Microsoft.EntityFrameworkCore.Infrastructure.Annotatable.EnsureMutable()
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.RemoveAnnotation(String name)
   at Microsoft.EntityFrameworkCore.Infrastructure.Annotatable.Microsoft.EntityFrameworkCore.Metadata.IMutableAnnotatable.RemoveAnnotation(String name)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.SnapshotModelProcessor.Process(IReadOnlyModel model, Boolean resetVersion)
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language, Boolean dryRun)

my scaffold code:

var services = new ServiceCollection().AddEntityFrameworkDesignTimeServices().AddDbContextDesignTimeServices(context);

 var designTimeServices = new SqlServerDesignTimeServices();
 designTimeServices.ConfigureDesignTimeServices(services);

 var serviceProvider = services.BuildServiceProvider();
 var scaffolder = serviceProvider.GetRequiredService<IMigrationsScaffolder>();

 var migrationPath = Path.Combine(Hosting.ContentRootPath, @"..\", SystemName, "Migrations", DbContext.UseSqlServerProvider ? "SqlServer" : "NpgSql");
 if (!Directory.Exists(migrationPath)) Directory.CreateDirectory(migrationPath);

 var migration = scaffolder.ScaffoldMigration("my-migration-name","namespace"); 
@cincuranet
Copy link
Contributor

This issue is lacking enough information for us to be able to fully understand what is happening. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@oONoobMasterOo
Copy link
Author

here is my full scaffold code that worked perfectly at version 8.0.11:

using (var DbContext = Activator.CreateInstance(MainDbContext, DbContextOptionsBuilderObject.Options, HttpContextAccessor) as DbContext)
{
    var relationalDatabaseCreator = DbContext.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
    var databaseExists = await relationalDatabaseCreator.ExistsAsync();
    var hasDifferences = false;

    var Migrations = DbContext.Database.GetMigrations();
    var migrationsAssembly = DbContext.GetService<IMigrationsAssembly>();
    if (migrationsAssembly.ModelSnapshot != null)
    {
        var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;

        if (snapshotModel is IMutableModel mutableModel)
        {
            snapshotModel = mutableModel.FinalizeModel();
        }

        if (snapshotModel != null)
        {
            snapshotModel = DbContext.GetService<IModelRuntimeInitializer>().Initialize(snapshotModel);
        }

        hasDifferences = DbContext.GetService<IMigrationsModelDiffer>().HasDifferences(snapshotModel?.GetRelationalModel(), DbContext.GetService<IDesignTimeModel>().Model?.GetRelationalModel());
    }
    if (!databaseExists || hasDifferences || migrationsAssembly.ModelSnapshot == null)
    {
        var services = new ServiceCollection().AddEntityFrameworkDesignTimeServices().AddDbContextDesignTimeServices(DbContext);

        var designTimeServices = new SqlServerDesignTimeServices();
        designTimeServices.ConfigureDesignTimeServices(services);

        var serviceProvider = services.BuildServiceProvider();
        var scaffolder = serviceProvider.GetRequiredService<IMigrationsScaffolder>();

        var migrationPath = Path.Combine(Hosting.ContentRootPath, @"..\", SystemName, "Migrations", DbContext.UseSqlServerProvider ? "SqlServer" : "NpgSql");
        if (!Directory.Exists(migrationPath)) Directory.CreateDirectory(migrationPath);

        var migration = scaffolder.ScaffoldMigration($"Migration-test1", $"Company.Systems.{SystemName}", $"Migrations.{(DbContext.UseSqlServerProvider ? "SqlServer" : "NpgSql")}");

        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.MigrationId + migration.FileExtension), migration.MigrationCode);
        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.MigrationId + ".Designer" + migration.FileExtension), migration.MetadataCode);
        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.SnapshotName + migration.FileExtension), migration.SnapshotCode);

        result.Add(new(true, "Main DbContext Scaffolded"));
    }
}

the exception happens at scaffolder.ScaffoldMigration()

@AndriySvyryd AndriySvyryd self-assigned this Nov 20, 2024
@AndriySvyryd
Copy link
Member

I'm not sure why you scaffold a new migration when the database doesn't exist, but try replacing hasDifferences || migrationsAssembly.ModelSnapshot == null with DbContext.Database.HasPendingModelChanges() and remove all the code that's no longer necessary:

using (var DbContext = Activator.CreateInstance(MainDbContext, DbContextOptionsBuilderObject.Options, HttpContextAccessor) as DbContext)
{
    var relationalDatabaseCreator = DbContext.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
    var databaseExists = await relationalDatabaseCreator.ExistsAsync();
    if (!databaseExists || DbContext.Database.HasPendingModelChanges())
    {
        var services = new ServiceCollection().AddEntityFrameworkDesignTimeServices().AddDbContextDesignTimeServices(DbContext);

        var designTimeServices = new SqlServerDesignTimeServices();
        designTimeServices.ConfigureDesignTimeServices(services);

        var serviceProvider = services.BuildServiceProvider();
        var scaffolder = serviceProvider.GetRequiredService<IMigrationsScaffolder>();

        var migrationPath = Path.Combine(Hosting.ContentRootPath, @"..\", SystemName, "Migrations", DbContext.UseSqlServerProvider ? "SqlServer" : "NpgSql");
        if (!Directory.Exists(migrationPath)) Directory.CreateDirectory(migrationPath);

        var migration = scaffolder.ScaffoldMigration($"Migration-test1", $"Company.Systems.{SystemName}", $"Migrations.{(DbContext.UseSqlServerProvider ? "SqlServer" : "NpgSql")}");

        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.MigrationId + migration.FileExtension), migration.MigrationCode);
        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.MigrationId + ".Designer" + migration.FileExtension), migration.MetadataCode);
        await System.IO.File.WriteAllTextAsync(Path.Combine(migrationPath, migration.SnapshotName + migration.FileExtension), migration.SnapshotCode);

        result.Add(new(true, "Main DbContext Scaffolded"));
    }
}

@oONoobMasterOo
Copy link
Author

I've used your code but am still encountering the error.

I’d like to debug it myself. Could you let me know which EF Core projects I should reference?

@oONoobMasterOo
Copy link
Author

👀

@oONoobMasterOo
Copy link
Author

any due date?

@oONoobMasterOo
Copy link
Author

any workarounds please? cause my migration to .NET 9 is stopped due to that issue.

Thanks

@AndriySvyryd
Copy link
Member

@oONoobMasterOo I am still unable to repro this issue locally. But you can try adding a new migration manually before running the code.

AndriySvyryd added a commit that referenced this issue Jan 8, 2025
@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jan 8, 2025
@AndriySvyryd AndriySvyryd added this to the 10.0.0 milestone Jan 8, 2025
@AndriySvyryd AndriySvyryd removed their assignment Jan 8, 2025
@AndriySvyryd AndriySvyryd linked a pull request Jan 8, 2025 that will close this issue
@oONoobMasterOo
Copy link
Author

Hi,

During the initial migration without a snapshot, it works well, but subsequent migrations result in the same error. However, performing the using the standard command line works without issues. would like to know which project to reference to debug this issue in my environment.

regards.

@oONoobMasterOo
Copy link
Author

ScaffoldMigration.zip
Here is a reproducible sample application.

@AndriySvyryd
Copy link
Member

would like to know which project to reference to debug this issue in my environment.

You'd need to reference EFCore.Design, EFCore.PG and all the projects they reference. Setting up a debugging environment will not be straightforward.

@AndriySvyryd
Copy link
Member

ScaffoldMigration.zip
Here is a reproducible sample application.

I see, this happens because you call this before scaffolding a migration:

if (_appDbContext.Database.GetPendingMigrations().Any())
{
    _appDbContext.Database.Migrate();
}

#35432 Will fix this.

@oONoobMasterOo
Copy link
Author

cool, when this fix gets released?

@AndriySvyryd
Copy link
Member

cool, when this fix gets released?

It will be in EF Core 10 preview releasing in a couple of months.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-migrations closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants