diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index 9d854645ae7..026f9cfea1c 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -1147,13 +1147,28 @@ SqlExpression GeneratePredicateTpt(StructuralTypeProjectionExpression entityProj { var concreteEntityTypes = derivedType.GetConcreteDerivedTypesInclusive().ToList(); var discriminatorColumn = BindProperty(typeReference, discriminatorProperty); + + // Apply any value conversion to the discriminator values. + // Note that this is important also to get the correct SqlConstantExpression.Type, which needs to be the provider type + // rather than the model type; this is in line with how we translate constants everywhere else, and is important in order + // for comparison logic between constants to function correctly (see #32865). + var converter = discriminatorColumn.TypeMapping?.Converter?.ConvertToProvider; + return concreteEntityTypes.Count == 1 ? _sqlExpressionFactory.Equal( discriminatorColumn, - _sqlExpressionFactory.Constant(concreteEntityTypes[0].GetDiscriminatorValue())) + _sqlExpressionFactory.Constant(GetDiscriminatorValue(concreteEntityTypes[0]))) : _sqlExpressionFactory.In( discriminatorColumn, - concreteEntityTypes.Select(et => _sqlExpressionFactory.Constant(et.GetDiscriminatorValue())).ToArray()); + concreteEntityTypes.Select(et => _sqlExpressionFactory.Constant(GetDiscriminatorValue(et))).ToArray()); + + object? GetDiscriminatorValue(IEntityType entityType) + => entityType.GetDiscriminatorValue() switch + { + object value when converter is not null => converter(value), + object value => value, + null => null + }; } return _sqlExpressionFactory.Constant(true); diff --git a/test/EFCore.Specification.Tests/Query/AdHocMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/AdHocMiscellaneousQueryTestBase.cs index 7a3ee6fe517..9d5bd98434f 100644 --- a/test/EFCore.Specification.Tests/Query/AdHocMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/AdHocMiscellaneousQueryTestBase.cs @@ -2382,4 +2382,42 @@ public class CompanyDto : ICompanyDto } #endregion + + #region // #32865 + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task OfType_on_enum_discriminator_with_Where_on_same_discriminator(bool async) + { + var contextFactory = await InitializeAsync(); + await using var context = contextFactory.CreateContext(); + + context.Add(new Context32865.SpecialBlog()); + await context.SaveChangesAsync(); + + Assert.Equal(1, await context.Set() + .OfType() + .CountAsync(b => b.Type == Context32865.BlogType.Special)); + } + + private class Context32865(DbContextOptions options) : DbContext(options) + { + protected override void OnModelCreating(ModelBuilder modelBuilder) + => modelBuilder.Entity() + .HasDiscriminator(e => e.Type) + .HasValue(BlogType.Regular) + .HasValue(BlogType.Special); + + public class Blog + { + public int Id { get; set; } + public BlogType Type { get; set; } + } + + public class SpecialBlog : Blog; + + public enum BlogType { Regular, Special } + } + + #endregion // #32865 } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs index 1161d1b89e5..5839e27c525 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs @@ -2317,6 +2317,28 @@ WHERE CASE WHEN [c0].[Id] IS NOT NULL THEN [c1].[CountryName] ELSE NULL END = N'COUNTRY' +"""); + } + + public override async Task OfType_on_enum_discriminator_with_Where_on_same_discriminator(bool async) + { + await base.OfType_on_enum_discriminator_with_Where_on_same_discriminator(async); + + AssertSql( + """ +@p0='1' + +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [Blog] ([Type]) +OUTPUT INSERTED.[Id] +VALUES (@p0); +""", + // +""" +SELECT COUNT(*) +FROM [Blog] AS [b] +WHERE [b].[Type] = 1 """); } }