diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 8ce5687a98e..1ad9922a7e5 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -8,6 +8,9 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal; public partial class NavigationExpandingExpressionVisitor { + private static readonly bool UseOldBehavior37478 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37478", out var enabled) && enabled; + /// /// Expands navigations in the given tree for given source. /// Optionally also expands navigations for includes. @@ -123,6 +126,16 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp if (structuralType is not null) { + if (!UseOldBehavior37478 && entityReference is not null && convertedType is not null) + { + structuralType = entityReference.EntityType.GetAllBaseTypes().Concat(entityReference.EntityType.GetDerivedTypesInclusive()) + .FirstOrDefault(et => et.ClrType == convertedType); + if (structuralType == null) + { + return null; + } + } + var complexProperty = memberIdentity.MemberInfo != null ? structuralType.FindComplexProperty(memberIdentity.MemberInfo) : memberIdentity.Name is not null diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryCosmosTest.cs index 0051b5c31ee..8532978a832 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryCosmosTest.cs @@ -362,6 +362,18 @@ FROM root c """); } + public override async Task Subquery_over_primitive_collection_on_inheritance_derived_type() + { + await base.Subquery_over_primitive_collection_on_inheritance_derived_type(); + + AssertSql( + """ +SELECT VALUE c +FROM root c +WHERE ((c["$type"] = "SubType") AND (ARRAY_LENGTH(c["Ints"]) > 0)) +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryTestBase.cs index 0fe3f76ce6e..7c82cb164db 100644 --- a/test/EFCore.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryTestBase.cs @@ -256,6 +256,33 @@ private class Owned public int Foo { get; set; } } + [ConditionalFact] // #37478 + public virtual async Task Subquery_over_primitive_collection_on_inheritance_derived_type() + { + var contextFactory = await InitializeAsync( + onModelCreating: mb => + { + mb.Entity(); + mb.Entity(); + }); + + await using var context = contextFactory.CreateContext(); + + _ = await context.Set() + .Where(x => ((SubType)x).Ints.Any()) + .ToListAsync(); + } + + public abstract class BaseType + { + public int Id { get; set; } + } + + public class SubType : BaseType + { + public required int[] Ints { get; set; } + } + /// /// A utility that allows easy testing of querying out arbitrary element types from a primitive collection, provided two distinct /// element values. diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs index abb3d8dc890..71a755d1e22 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs @@ -1026,6 +1026,20 @@ WHERE [t].[Id] IN (@ints1, @ints2, @ints3, @ints4, @ints5, @ints6, @ints7, @ints """); } + public override async Task Subquery_over_primitive_collection_on_inheritance_derived_type() + { + await base.Subquery_over_primitive_collection_on_inheritance_derived_type(); + + AssertSql( + """ +SELECT [b].[Id], [b].[Discriminator], [b].[Ints] +FROM [BaseType] AS [b] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON([b].[Ints]) AS [i]) +"""); + } + [ConditionalFact] public virtual async Task Same_parameter_with_different_type_mappings() {