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.63k stars 3.15k forks source link

Generating new ModelSnapshot removes type and name for HasDiscriminator leading to null reference exception in 8.0.7 #34201

Closed SandstromErik closed 1 day ago

SandstromErik commented 1 month ago

When I try to add a new migration which generates a new ModelSnapshot, type and name is removed from HasDescriminator in modelBuilder.Entity. I have discriminator configured in a seperate configuration file.

For example, in my configuration file I have

internal class MyEntityBaseConfiguration : IEntityTypeConfiguration<MyEntityBase>
{
    public void Configure(EntityTypeBuilder<MyEntityBase> builder)
    {
        builder.HasKey(x => x.Id);

        builder.HasDiscriminator<byte>("Discriminator")
            .HasValue<MyEntityBase>(0)
            .HasValue<MyFirstEntity>(1)
            .HasValue<MySecondEntity>(2);
    }
}

In version 8.0.6 this results in the following when the ModelSnapshot is generated

modelBuilder.Entity("MyNamespace.MyEntityBase", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");

                    b.Property<byte>("Discriminator")
                        .HasColumnType("tinyint");

                    b.HasKey("Id");

                    b.ToTable("MyEntityBases", "dbo");

                    b.HasDiscriminator<byte>("Discriminator").HasValue((byte)0);

                    b.UseTphMappingStrategy();
                });

But now the generated snapshot looks like this, which results in a null reference exception when I try to add a new migration

modelBuilder.Entity("MyNamespace.MyEntityBase", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");

                    b.Property<byte>("Discriminator")
                        .HasColumnType("tinyint");

                    b.HasKey("Id");

                    b.ToTable("MyEntityBases", "dbo");

                    b.HasDiscriminator().HasValue((byte)0);

                    b.UseTphMappingStrategy();
                });

Callstack:

System.NullReferenceException: Object reference not set to an instance of an object.
   at MyModelSnapshot.<>c.<BuildModel>b__0_201(EntityTypeBuilder b) in C:\xxx.MyModelSnapshot.cs:line XXX
   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity(String name, Action`1 buildAction)
   at MyModelSnapshot.BuildModel(ModelBuilder modelBuilder) in C:\xxx.MyModelSnapshot.cs:line XXX
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot.CreateModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot.get_Model()
   at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Provider and version information

EF Core version: 8.0.7 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 8.0 Operating system: Windows 11 IDE: Visual Studio 2022 17.10

rmja commented 1 month ago

Please let us know if there is an easy workaround for this. It seems that uninstalling the global tool and install a previous version explicitly does not work. It still seems to produce with the 8.0.7 version. That is dotnet tool list -g outputs:

Package Id      Version      Commands      Manifest
---------------------------------------------------
PS C:\Source\Utiliread\src\Catalog> dotnet tool list -g
Package Id          Version         Commands
----------------------------------------------------
dotnet-ef           8.0.4           dotnet-ef

yet the version number in the migration snapshot still indicates 8.0.7.

zmerdev commented 1 month ago

Confirmed this is an 8.0.7 problem. TPH classes with an explicit discriminator table for all types causes the model snapshot to break. Rolling back the migration changes that were generated with 8.0.7 in git and regenerating them in 8.0.6 fixes the issue.

markjhewitt75 commented 1 month ago

+1 for confirmation. System.NullReferenceException: Object reference not set to an instance of an object on TPH class - breaks on HasDiscriminator() line. Revert to 8.0.6 fixed.

markushaslinger commented 1 month ago

Please let us know if there is an easy workaround for this. It seems that uninstalling the global tool and install a previous version explicitly does not work. It still seems to produce with the 8.0.7 version. That is dotnet tool list -g outputs:

Package Id      Version      Commands      Manifest
---------------------------------------------------
PS C:\Source\Utiliread\src\Catalog> dotnet tool list -g
Package Id          Version         Commands
----------------------------------------------------
dotnet-ef           8.0.4           dotnet-ef

yet the version number in the migration snapshot still indicates 8.0.7.

I had the same issue, then realized I downgraded the tool, but not the packages in the project. After doing that as well I got a working migration from 8.0.6

Leaving this here in case anyone else also didn't have their coffee yet ;)

ivan-84 commented 4 weeks ago

@SandstromErik and all, my colleagues and I were investigating this issue today and by following the changes recently made to EF Core code, we've managed to overcome this quite easily - all you need to do in order to make it work with 8.0.7 is to re-name your discriminator column from "Discriminator" to something else, say "MyEntityTypeDiscriminator" - that's it, after that generated snapshot appears to be correct and looks exactly the same as with 8.0.6.

LukeThoma5 commented 4 weeks ago

Additionally if you can't change the database schema for any reason, renaming the EF entity property and forcing the column name of "Discriminator" also works.