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
EF8 core: filtering by enum doesn't work with TPH and OfType #32865
Comments
Note for triage: still repros on the latest daily build; regression from EF7. Daily generates:
EF7 generates:
Code: using (var context = new SomeDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
await context.SaveChangesAsync();
}
using (var context = new SomeDbContext())
{
var results = context.Set<StorageDTechnologyDto>()
.OfType<StorageDTechnologyDtoC>()
.Where(x => (x.TechnologyType == TechnologyType.StorageA
|| x.TechnologyType == TechnologyType.StorageB
|| x.TechnologyType == TechnologyType.StorageC
|| x.TechnologyType == TechnologyType.StorageD))
.ToList();
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=localhost;Database=One;Integrated Security=True;TrustServerCertificate=true")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StorageDTechnologyDto>()
.HasDiscriminator(e => e.TechnologyType)
.HasValue<StorageDTechnologyDtoA>(TechnologyType.StorageA)
.HasValue<StorageDTechnologyDtoB>(TechnologyType.StorageB)
.HasValue<StorageDTechnologyDtoC>(TechnologyType.StorageC)
.HasValue<StorageDTechnologyDtoD>(TechnologyType.StorageD);
}
}
public abstract class StorageDTechnologyDto
{
public int Id { get; set; }
public TechnologyType TechnologyType { get; set; }
}
public class StorageDTechnologyDtoA : StorageDTechnologyDto
{
}
public class StorageDTechnologyDtoB : StorageDTechnologyDto
{
}
public class StorageDTechnologyDtoC : StorageDTechnologyDto
{
}
public class StorageDTechnologyDtoD : StorageDTechnologyDto
{
}
public enum TechnologyType
{
StorageA,
StorageB,
StorageC,
StorageD
} |
The regression was introduced in #31046, where SqlExpressionSimplifyingExpressionVisitor was changed to compare SqlConstantExpressions instead of bare .NET values, making it more sensitive to subtle differences between expression nodes. The problem here is that the OfType() code path creates SqlConstantExpressions for discriminator columns based on the pre-converted value (so enum instead of underlying int (here), whereas in other places in the query pipeline (e.g. regular Where comparison) the SqlConstantExpression gets the underlying type instead; the Type property on the nodes mismatch, leading to the bug. The root cause is that we don't apply the discriminator's value converter to the (model) values stored in the model; we enabled value converters on discriminator columns in #19650 back in 5.0, but didn't modify OfType() accordingly. |
Code
context.Technologies has TPH, discriminator is based on TechnologyType enum (8 different values)
Case:
Include verbose output
.NET 8 & EF core 8.0.1 produces WHERE 0 = 1
It worked in .NET 7 & EF7
Workaround
Replace
by
Include provider and version information
EF Core version: core 8.0.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows & Linux
IDE: Visual Studio 2022 17.8.4
The text was updated successfully, but these errors were encountered: