dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.77k stars 3.18k forks source link

HasPendingModelChanges() always returns true #34967

Open charlesRollandy opened 1 week ago

charlesRollandy commented 1 week ago

I have an application with a database project and a data migration project. I wrote a unit test in a dedicated project to test there is no pending changes in my model and no migration is required.

My solution has the following structure:

MySolution
├ Database/
|    ├ Entities/
|    |     User.cs
|    |     Group.cs
|    |     ...
|    AppDbContext.cs   
├ Database.Migrations/
|    ├ Migrations/
|    DesignTimeDbContextFactory.cs
├ App.UnitTests/
|    AppDbContextTests.cs   

This us my unit test in AppDbContext.cs:

public class AppDbContextTests
{
    [Test]
    public void Database_shouldNotHavePendingModelChanges()
    {
        using(var context = CreateAppDbContext())
        {
            var hasChanges = context.Database.HasPendingModelChanges();
            Assert.That(hasChanges, Is.False, "The dabatase has model changes pending. Create a new migration for it.");
        }        
    }

    private AppDbContext CreateAppDbContext()
    {
        var connection = new SqliteConnection("Filename=:memory:");
        connection.Open();

        var dbContextOptions = new DbContextOptionsBuilder<AppDbContext>()
            .UseSqlite(
                connection,
                b => b.MigrationsAssembly(Assembly.GetAssembly(typeof(DesignTimeDbContextFactory))!.GetName().Name))
            .Options;

        return new AppDbContext(dbContextOptions);
    }
}

This test always fails. HasPendingModelChanges always returns true

This is the code of DesignTimeDbContextFactory.cs

public class DesignTimeDbContextFactory: IDesignTimeDbContextFactory<AppDbContext>
{
    public AppDbContext CreateDbContext(string[] args)
    {
        // Build config
        IConfiguration config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
# if DEBUG
            .AddJsonFile($"appsettings.local.json")
#endif
            .AddEnvironmentVariables()
            .Build();

        // Get connection string
        var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
        optionsBuilder.UseSqlServer(config.GetValue<string>(AppDbContext.ConfigurationKey),
            b => b.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name));
        return new AppDbContext(optionsBuilder.Options);
    }
}

When I open a terminal from the Database.Migrations folder and run the command dotnet ef migrations has-pending-model-changes it gives me the correct result. I tried using the same database provider in my unit test but the result was the same. It doesn't look to be related to that.

EF Core version: 8.0.10 Target framework: (e.g. .NET 8.0) Operating system: Windows 11 IDE: (e.g. Visual Studio 2022 17.11.5)

ajcvickers commented 5 days ago

@charlesRollandy I may be missing something here, but if you create a new, empty, SQLite in-memory database, then the schema will be empty and HasPendingModelChanges should always return true.

charlesRollandy commented 18 hours ago

@ajcvickers HasPendingModelChanges is not looking if the model changes are applied to the database but if some changes into the entities are not reflected with migrations.

What is actually weird is that the cli provides the correct result but not the method from the SDK. Could if be related to configuration ?