From 0d426476ab69694d9102c8bbd0090463ed20d4c3 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Tue, 1 Mar 2022 17:20:10 -0800 Subject: [PATCH] Fix to #27356 - Collection_navigation_equal_to_null_for_subquery fails after merging from release/6.0 (#27429) Improvement on the previous patch fix (#26744). We were not taking into the account scenario where collection projected from FirstOrDefault was compared to null. Collection can only be null if the parent entity is null, so we can safely apply the same optimization we do for anonymous types and required entities. Fixes #27356 --- .../InMemoryExpressionTranslatingExpressionVisitor.cs | 3 ++- .../Query/RelationalSqlTranslatingExpressionVisitor.cs | 3 ++- .../Query/NorthwindMiscellaneousQueryTestBase.cs | 2 +- .../Query/NorthwindMiscellaneousQuerySqlServerTest.cs | 7 +++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs index 865fa04f540..d999cf5128a 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs @@ -204,7 +204,8 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) { var projection = translatedSubquery.ShaperExpression; if (projection is NewExpression - || RemoveConvert(projection) is EntityShaperExpression { IsNullable: false }) + || RemoveConvert(projection) is EntityShaperExpression { IsNullable: false } + || RemoveConvert(projection) is CollectionResultShaperExpression) { var anySubquery = Expression.Call( QueryableMethods.AnyWithoutPredicate.MakeGenericMethod(translatedSubquery.Type.GetSequenceType()), diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index 73b09d7142f..de33b433567 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -367,7 +367,8 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) { var projection = translatedSubquery.ShaperExpression; if (projection is NewExpression - || RemoveConvert(projection) is EntityShaperExpression { IsNullable: false }) + || RemoveConvert(projection) is EntityShaperExpression { IsNullable: false } + || RemoveConvert(projection) is CollectionResultExpression) { var anySubquery = Expression.Call( QueryableMethods.AnyWithoutPredicate.MakeGenericMethod(translatedSubquery.Type.GetSequenceType()), diff --git a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs index 286764bb670..45bcb45f5e4 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs @@ -5546,7 +5546,7 @@ protected static bool ClientEvalPredicate(Order order) protected internal uint ClientEvalSelector(Order order) => order.EmployeeID % 10 ?? 0; - [ConditionalTheory(Skip = "Issue#20445")] + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Collection_navigation_equal_to_null_for_subquery(bool async) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index cc0ab6a34cc..af557051949 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -4589,11 +4589,10 @@ public override async Task Collection_navigation_equal_to_null_for_subquery(bool AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE ( - SELECT TOP(1) [o].[OrderID] +WHERE NOT (EXISTS ( + SELECT 1 FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[OrderID]) IS NULL"); + WHERE [c].[CustomerID] = [o].[CustomerID]))"); } public override async Task Dependent_to_principal_navigation_equal_to_null_for_subquery(bool async)