From 5a799cf403df78649d19aa7b357e5c6820b82233 Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Fri, 12 Jun 2020 00:08:15 -0700 Subject: [PATCH] Query: Process client eval in join when collection shaper Extension of #19247 for collection shaper in client eval --- ...ionalProjectionBindingExpressionVisitor.cs | 7 ++++ .../Query/NorthwindJoinQueryCosmosTest.cs | 12 +++++++ .../Query/NorthwindJoinQueryInMemoryTest.cs | 12 +++++++ .../Query/NorthwindJoinQueryTestBase.cs | 35 +++++++++++++++++-- .../Query/NorthwindJoinQuerySqlServerTest.cs | 35 ++++++++++++++++++- .../Query/NorthwindJoinQuerySqliteTest.cs | 2 ++ 6 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs index cd0546d5f2f..da1fadf1fb0 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs @@ -291,6 +291,13 @@ protected override Expression VisitExtension(Expression extensionExpression) : null; } + if (extensionExpression is CollectionShaperExpression) + { + return _clientEval + ? extensionExpression + : null; + } + throw new InvalidOperationException( CoreStrings.QueryFailed(extensionExpression.Print(), GetType().Name)); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindJoinQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindJoinQueryCosmosTest.cs index 56817affdfa..4de9799d559 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindJoinQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindJoinQueryCosmosTest.cs @@ -510,6 +510,18 @@ public override Task SelectMany_with_client_eval(bool async) return base.SelectMany_with_client_eval(async); } + [ConditionalTheory(Skip = "Issue#17246")] + public override Task SelectMany_with_client_eval_with_collection_shaper(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper(async); + } + + [ConditionalTheory(Skip = "Issue#17246")] + public override Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper_ignored(async); + } + [ConditionalTheory(Skip = "Issue#17246")] public override Task SelectMany_with_client_eval_with_constructor(bool async) { diff --git a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindJoinQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/NorthwindJoinQueryInMemoryTest.cs index c670d8bc152..37dd74d9169 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/NorthwindJoinQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/NorthwindJoinQueryInMemoryTest.cs @@ -26,6 +26,18 @@ public override Task SelectMany_with_client_eval(bool async) return base.SelectMany_with_client_eval(async); } + [ConditionalTheory(Skip = "Issue#21200")] + public override Task SelectMany_with_client_eval_with_collection_shaper(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper(async); + } + + [ConditionalTheory(Skip = "Issue#21200")] + public override Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper_ignored(async); + } + [ConditionalTheory(Skip = "Issue#21200")] public override Task SelectMany_with_client_eval_with_constructor(bool async) { diff --git a/test/EFCore.Specification.Tests/Query/NorthwindJoinQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindJoinQueryTestBase.cs index 560881026ad..462171d329f 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindJoinQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindJoinQueryTestBase.cs @@ -738,10 +738,41 @@ public virtual Task SelectMany_with_client_eval(bool async) { return AssertQuery( async, - ss => ss.Set() + ss => ss.Set().Where(c => c.CustomerID.StartsWith("F")) .SelectMany(c => c.Orders.Select(o => new { OrderProperty = ClientMethod(o), CustomerProperty = c.ContactName })), elementSorter: e => e.OrderProperty, - entryCount: 830); + entryCount: 63); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task SelectMany_with_client_eval_with_collection_shaper(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("F")) + .SelectMany(c => c.Orders.Select(o => new { OrderProperty = ClientMethod(o), o.OrderDetails, CustomerProperty = c.ContactName })), + elementSorter: e => e.OrderProperty, + elementAsserter: (e, a) => + { + AssertEqual(e.OrderProperty, a.OrderProperty); + AssertEqual(e.CustomerProperty, a.CustomerProperty); + AssertCollection(e.OrderDetails, a.OrderDetails); + }, + entryCount: 227); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("F")) + .SelectMany(c => c.Orders.Select(o => new { OrderProperty = ClientMethod(o), o.OrderDetails, CustomerProperty = c.ContactName })) + .Select(e => new { e.OrderProperty, e.CustomerProperty }), + elementSorter: e => e.OrderProperty, + entryCount: 63); } private static int ClientMethod(Order order) => order.OrderID; diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs index 52ebf90fbff..fe3b5e4c5d7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs @@ -524,7 +524,40 @@ CROSS APPLY ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[ContactName] FROM [Orders] AS [o] WHERE [c].[CustomerID] = [o].[CustomerID] -) AS [t]"); +) AS [t] +WHERE [c].[CustomerID] LIKE N'F%'"); + } + + public override async Task SelectMany_with_client_eval_with_collection_shaper(bool async) + { + await base.SelectMany_with_client_eval_with_collection_shaper(async); + + AssertSql( + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[ContactName], [c].[CustomerID], [t].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] +FROM [Customers] AS [c] +CROSS APPLY ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[ContactName] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] +) AS [t] +LEFT JOIN [Order Details] AS [o0] ON [t].[OrderID] = [o0].[OrderID] +WHERE [c].[CustomerID] LIKE N'F%' +ORDER BY [c].[CustomerID], [t].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + } + + public override async Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) + { + await base.SelectMany_with_client_eval_with_collection_shaper_ignored(async); + + AssertSql( + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[ContactName] +FROM [Customers] AS [c] +CROSS APPLY ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[ContactName] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] +) AS [t] +WHERE [c].[CustomerID] LIKE N'F%'"); } public override async Task SelectMany_with_client_eval_with_constructor(bool async) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindJoinQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindJoinQuerySqliteTest.cs index 21f57411a21..5071d1045dc 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindJoinQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindJoinQuerySqliteTest.cs @@ -18,5 +18,7 @@ public NorthwindJoinQuerySqliteTest(NorthwindQuerySqliteFixture Task.CompletedTask; + public override Task SelectMany_with_client_eval_with_collection_shaper(bool async) => Task.CompletedTask; + public override Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) => Task.CompletedTask; } }