I have several applications I am creating with NET9 using Entity Framework Core that returns PendingModelChangesWarning. I found out how to understand this error better.
Scenario
In one of my Blazor projects, I added some APIs that save data in the database using Entity Framework Core. Because it was in NET8, I updated the project to NET9. After the update, I ran again the application and I got the following error:
An unhandled exception has occurred while executing the request. System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Migrations.PendingModelChangesWarning': The model for context 'TracksContext' has pending changes. Add a new migration before updating the database. This exception can be suppressed or logged by passing event ID 'RelationalEventId.PendingModelChangesWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'. at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition`1.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, TParam arg) at Microsoft.EntityFrameworkCore.Diagnostics.RelationalLoggerExtensions.PendingModelChangesWarning(IDiagnosticsLogger`1 diagnostics, Type contextType) at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(Func`4 seed, String targetMigration, Nullable`1 lockTimeout, CancellationToken cancellationToken) at MartinCostello.AppleFitnessWorkoutMapper.Services.TrackImporter.ImportTracksAsync(CancellationToken cancellationToken) in /_/src/AppleFitnessWorkoutMapper/Services/TrackImporter.cs:line 27 at Program.<>c.<<<Main>$>b__0_12>d.MoveNext() in /_/src/AppleFitnessWorkoutMapper/Program.cs:line 201 --- End of stack trace from previous location --- at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F2A4F9050321DD26474371351A8857FE053630885E7CB9BFF3B12464F0B87EE32__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass6_0.<<MapPost3>g__RequestHandler|5>d.MoveNext() in /_/artifacts/obj/AppleFitnessWorkoutMapper/release/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Microsoft.AspNetCore.Http.RequestDelegateGenerator.RequestDelegateGenerator/GeneratedRouteBuilderExtensions.g.cs:line 638 --- End of stack trace from previous location --- at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
In my point of view, this error is quite cryptic and I don’t understand where the problem was. If I tried to generate a migration for my project using
add-migration InitialMigration -Context MyContext
the error came up but with the previous version of Entity Framework, the migration was created without raising any complaints. I saw some issues on GitHub about it.
Quick check
So, at this point, I started to search PendingModelChangesWarning with NET9. Any of the suggestions I found were applied to my code. Here is a quick check:
If you’re using random values or dynamic values like Guid.NewGuid()
or DateTime.Now
for seeding data, the model changes every time you run the application. As a result, EFCore detects a difference and generates a new migration each time.
This is why you’re seeing the PendingModelChangesWarning
. It’s a warning that indicates the model has changed and you need to generate a new migration. However, in your case, this creates an infinite loop of migrations.
The recommendation to resolve this issue, always use constant values when seeding data. This ensures the model remains consistent, preventing unnecessary migrations. I found later that this is working. For more details, you can see the Microsoft documentation.
Issues with Identity Users and roles
Another common issue is related to the creation of Users and Roles using Identity. Some columns in the Roles and Users tables, despite being nullable
, must be initialized during seeding. For example, ConcurrencyStamp
and SecurityStamp
. To be aware of these columns, run the migration again. The new migration will show you these columns in the UpdateData
format. Only initialize these fields in the seed data. Something like this:
var Role1 = new IdentityRole()
{
Id = "6ac343b0-00ef-4a1c-8f64-68daaca77b5b",
Name = "Role1",
NormalizedName = "Role1".ToUpper(),
ConcurrencyStamp = "6ac343b0-00ef-4a1c-8f64-68daaca77b5b"
};
builder.Entity<IdentityRole>().HasData(Role1s);
var adminUser = new IdentityUser()
{
Id = "08beacc0-38dd-42a9-82c1-c3706a0cf19e",
Email = "admin@puresourcecode.com",
NormalizedEmail = "admin@puresourcecode.com".ToUpper(),
UserName = "admin@puresourcecode.com",
NormalizedUserName = "admin@puresourcecode.com".ToUpper(),
ConcurrencyStamp = "08beacc0-38dd-42a9-82c1-c3706a0cf19e",
SecurityStamp = "08beacc0-38dd-42a9-82c1-c3706a0cf19e",
PasswordHash = "$2y$10$bDDaBlqNVSIfhAL7UBFjA2sDVVQABeMd"
};
builder.Entity<IdentityUser>().HasData(adminUser);
Although I create users and roles, this is not my case
Snapshots
Entity Framework Core compares two versions of your model to detect the changes. It compares snapshots from the last migration and the current state.
When your model contains some random generated value which is re-evaluated every time to a new value (like using Guid.NewGuid()) as the Id of some seed entity), the new value is considered as a change to the model. The recommended approach would be to hardcode some specific values into your data seeding code. In your case, you are not initializing the Id
of seed IdentityRole
data.
But what are the consequences of suppressing the error? The purpose of this exception is only to avoid the situation in which a programmer makes changes to the model but forgets to create a migration. Then they get into updating the database and not see the expected changes. Hence, I think the only downside of suppressing this error is that you may get into that situation.
The main motivation behind this change was something that happens often: you make some change to your model (e.g. add a property), and then you forget to actually add a migration to apply it to the database. You run
MigrateAsync()
(or similar) and can’t figure out why your database hasn’t been updated. The new error clearly tells you that your model contains changes with respect to the last migration snapshot. In other words, the point here is to help you avoid accidental error.
Solution
After a few hours of binging and googling, I discovered that it is possible to get more details about the error adding those lines in the configuration of the context:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(cnnString)
.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
.EnableDetailedErrors()
);
So, those lines show more details about the error and the exact reason or reasons. In my case, the error was related to the configuration of the relation between 2 tables. So, nothing similar to the most common issues I found on the internet.
Wrap up
In conclusion, I hope this post about PendingModelChangesWarning with NET9 could helps you in find your error in the code. If you have any issue or update or you want to share your solution, please comment below or in the forum.