What can be the reason that EF Core can incorrectly read db context and set wrong enum types for database?
I had DB-First and scaffolded context and entities in my project. After it was found out there are unmapped enums in my db and my context, I created enums in Pascal case and mapped them to tables like this:
modelBuilder
.HasPostgresEnum<AutoStatus>()
.HasPostgresEnum<AnotherEnum>()
.HasPostgresEnum<AndAnotherEnum>();
modelBuilder.Entity<Auto>(entity =>
entity.Property(e => e.Status).HasColumnName("status")
.HasConversion<string>()
.HasDefaultValueSql(AutoStatus.InAssembly.ToString())
.HasColumnType(nameof(AutoStatus));
);
Next was created an "Initial" migration and I tried to update (create) database by this migration. But EF spat out error "42704: type "autostatus" does not exist".
So, migration, migration designer and model snapshot had another enums for some reason:
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:Enum:auto_status", "in_assembly,ready_to_test,in_test,ready_to_sale,sold")
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "auto_status", new[] { "in_assembly", "ready_to_test", "in_test", "ready_to_sale", "sold" });
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "auto_status", new[] { "in_assembly", "ready_to_test", "in_test", "ready_to_sale", "sold" });
Why still there are old enums, if nowhere in project aren't uses of old (snakecase) enums?
So, the solution was to call MapEnum onto NpgsqlDataSourceBuilder:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
dataSourceBuilder.MapEnum<AutoStatus>("auto_status");
var dataSource = dataSourceBuilder.Build();
builder.Services.AddDbContext<AutoDealerContext>(options => options.UseNpgsql(dataSource));
Enum:
public enum AutoStatus
{
InAssembly,
ReadyToTest,
InTest,
ReadyToSale
Sold
}
OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresEnum<AutoStatus>();
}
It is also important to note, that call .HasConversion<string>()
unecessary:
modelBuilder.Entity<Auto>(entity =>
{
entity.Property(e => e.Status)
.HasColumnName("status")
.HasDefaultValueSql("'in_assembly'");
}