diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs
index 07a042ad3eb..1ad9cd9124b 100644
--- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs
+++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs
@@ -15,6 +15,24 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal;
///
public partial class NavigationExpandingExpressionVisitor : ExpressionVisitor
{
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public static readonly bool UseOldBehavior32217 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32217", out var enabled32217) && enabled32217;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public static readonly bool UseOldBehavior32312 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32312", out var enabled32312) && enabled32312;
+
private static readonly PropertyInfo QueryContextContextPropertyInfo
= typeof(QueryContext).GetTypeInfo().GetDeclaredProperty(nameof(QueryContext.Context))!;
@@ -921,6 +939,11 @@ private Expression ProcessContains(NavigationExpansionExpression source, Express
source = (NavigationExpansionExpression)_pendingSelectorExpandingExpressionVisitor.Visit(source);
var queryable = Reduce(source);
+ if (!UseOldBehavior32217)
+ {
+ item = Visit(item);
+ }
+
return Expression.Call(QueryableMethods.Contains.MakeGenericMethod(queryable.Type.GetSequenceType()), queryable, item);
}
@@ -959,11 +982,16 @@ private NavigationExpansionExpression ProcessDistinct(NavigationExpansionExpress
return new NavigationExpansionExpression(result, navigationTree, navigationTree, parameterName);
}
- private static NavigationExpansionExpression ProcessSkipTake(
+ private NavigationExpansionExpression ProcessSkipTake(
NavigationExpansionExpression source,
MethodInfo genericMethod,
Expression count)
{
+ if (!UseOldBehavior32312)
+ {
+ count = Visit(count);
+ }
+
source.UpdateSource(Expression.Call(genericMethod.MakeGenericMethod(source.SourceElementType), source.Source, count));
return source;
@@ -1002,6 +1030,11 @@ private NavigationExpansionExpression ProcessElementAt(
source.ApplySelector(Expression.Convert(source.PendingSelector, returnType));
}
+ if (!UseOldBehavior32312)
+ {
+ index = Visit(index);
+ }
+
source.ConvertToSingleResult(genericMethod, index);
return source;
@@ -1560,11 +1593,16 @@ private GroupByNavigationExpansionExpression ProcessOrderByThenBy(
return new NavigationExpansionExpression(newSource, navigationTree, navigationTree, parameterName);
}
- private static GroupByNavigationExpansionExpression ProcessSkipTake(
+ private GroupByNavigationExpansionExpression ProcessSkipTake(
GroupByNavigationExpansionExpression groupBySource,
MethodInfo genericMethod,
Expression count)
{
+ if (!UseOldBehavior32312)
+ {
+ count = Visit(count);
+ }
+
groupBySource.UpdateSource(
Expression.Call(genericMethod.MakeGenericMethod(groupBySource.SourceElementType), groupBySource.Source, count));
diff --git a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs
index 8c1c21a1f66..0d1de5d6be7 100644
--- a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs
+++ b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs
@@ -136,4 +136,7 @@ public override Task Where_subquery_with_ElementAt_using_column_as_index(bool as
public override Task Where_compare_anonymous_types(bool async)
=> Task.CompletedTask;
+
+ public override Task Subquery_inside_Take_argument(bool async)
+ => Task.CompletedTask;
}
diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs
index 152ab14c8dd..1f2bcbe5c48 100644
--- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs
@@ -8286,6 +8286,87 @@ public virtual Task Set_operator_with_navigation_in_projection_groupby_aggregate
.GroupBy(x => new { x.Name })
.Select(x => new { x.Key.Name, SumOfLengths = x.Sum(xx => xx.Location.Length) }));
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ var numbers = new[] { 1, -1 };
+
+ return AssertQuery(
+ async,
+ ss => ss.Set().Where(x => numbers.Contains(x.Weapons.Any() ? 1 : 0)));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ var weapons = new[] { "Marcus' Lancer", "Dom's Gnasher" };
+
+ return AssertQuery(
+ async,
+ ss => ss.Set().Where(x => weapons.Contains(x.Weapons.OrderBy(w => w.Id).FirstOrDefault().Name)));
+ }
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Subquery_inside_Take_argument(bool async)
+ {
+ var numbers = new[] { 0, 1, 2 };
+
+ return AssertQuery(
+ async,
+ ss => ss.Set().OrderBy(x => x.Nickname).Select(
+ x => x.Weapons.OrderBy(g => g.Id).Take(numbers.OrderBy(xx => xx).Skip(1).FirstOrDefault())),
+ assertOrder: true,
+ elementAsserter: (e, a) => AssertCollection(e, a, ordered: true));
+ }
+
+ [ConditionalTheory(Skip = "issue #32303")]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ return AssertQuery(
+ async,
+ ss => ss.Set().OrderBy(x => x.Name).Select(
+ x => x.BornGears.OrderBy(g => g.FullName).Skip(x.StationedGears.Any() ? 1 : 0)));
+ }
+
+ [ConditionalTheory(Skip = "issue #32303")]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ return AssertQuery(
+ async,
+ ss => ss.Set().OrderBy(x => x.Nickname).Select(
+ x => x.Weapons.OrderBy(g => g.Id).Take(x.AssignedCity.Name.Length)));
+ }
+
+ [ConditionalTheory(Skip = "issue #32303")]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ var numbers = new[] { 0, 1, 2 };
+
+ return AssertQuery(
+ async,
+ ss => ss.Set().OrderBy(x => x.Nickname).Select(
+ x => x.Weapons.OrderBy(g => g.Id).Take(
+ ss.Set().OrderBy(xx => xx.Nickname).FirstOrDefault().AssignedCity.Name.Length)),
+ assertOrder: true,
+ elementAsserter: (e, a) => AssertCollection(e, a, ordered: true));
+ }
+
+ [ConditionalTheory(Skip = "issue #32303")]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ return AssertQuery(
+ async,
+ ss => ss.Set().OrderBy(x => x.Nickname).Select(
+ x => x.Weapons.OrderBy(g => g.Id).ElementAt(x.AssignedCity != null ? 1 : 0)));
+ }
+
protected GearsOfWarContext CreateContext()
=> Fixture.CreateContext();
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
index 75121329252..6d16d71b713 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
@@ -10151,6 +10151,108 @@ GROUP BY [s].[Name]
""");
}
+ public override async Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[1,-1]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
+FROM [Gears] AS [g]
+WHERE CASE
+ WHEN EXISTS (
+ SELECT 1
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]) THEN 1
+ ELSE 0
+END IN (
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+)
+""");
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__weapons_0='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
+FROM [Gears] AS [g]
+WHERE EXISTS (
+ SELECT 1
+ FROM OPENJSON(@__weapons_0) WITH ([value] nvarchar(max) '$') AS [w0]
+ WHERE [w0].[value] = (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) OR ([w0].[value] IS NULL AND (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) IS NULL))
+""");
+ }
+
+ public override async Task Subquery_inside_Take_argument(bool async)
+ {
+ await base.Subquery_inside_Take_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[0,1,2]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId]
+FROM [Gears] AS [g]
+LEFT JOIN (
+ SELECT [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[SynergyWithId]
+ FROM (
+ SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row]
+ FROM [Weapons] AS [w]
+ ) AS [t]
+ WHERE [t].[row] <= COALESCE((
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+ ORDER BY [n].[value]
+ OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0)
+) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName]
+ORDER BY [g].[Nickname], [g].[SquadId], [t0].[OwnerFullName], [t0].[Id]
+""");
+ }
+
+ public override async Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Skip_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_ElementAt_correlated_to_source(async);
+
+ AssertSql();
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
index 7a6806fd36f..d5ce36064db 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
@@ -13365,6 +13365,126 @@ GROUP BY [s].[Name]
""");
}
+ public override async Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[1,-1]' (Size = 4000)
+
+SELECT [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Discriminator]
+FROM (
+ SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], N'Gear' AS [Discriminator]
+ FROM [Gears] AS [g]
+ UNION ALL
+ SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
+ FROM [Officers] AS [o]
+) AS [t]
+WHERE CASE
+ WHEN EXISTS (
+ SELECT 1
+ FROM [Weapons] AS [w]
+ WHERE [t].[FullName] = [w].[OwnerFullName]) THEN 1
+ ELSE 0
+END IN (
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+)
+""");
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__weapons_0='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000)
+
+SELECT [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Discriminator]
+FROM (
+ SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], N'Gear' AS [Discriminator]
+ FROM [Gears] AS [g]
+ UNION ALL
+ SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator]
+ FROM [Officers] AS [o]
+) AS [t]
+WHERE EXISTS (
+ SELECT 1
+ FROM OPENJSON(@__weapons_0) WITH ([value] nvarchar(max) '$') AS [w0]
+ WHERE [w0].[value] = (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [t].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) OR ([w0].[value] IS NULL AND (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [t].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) IS NULL))
+""");
+ }
+
+ public override async Task Subquery_inside_Take_argument(bool async)
+ {
+ await base.Subquery_inside_Take_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[0,1,2]' (Size = 4000)
+
+SELECT [t].[Nickname], [t].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId]
+FROM (
+ SELECT [g].[Nickname], [g].[SquadId], [g].[FullName]
+ FROM [Gears] AS [g]
+ UNION ALL
+ SELECT [o].[Nickname], [o].[SquadId], [o].[FullName]
+ FROM [Officers] AS [o]
+) AS [t]
+LEFT JOIN (
+ SELECT [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId]
+ FROM (
+ SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row]
+ FROM [Weapons] AS [w]
+ ) AS [t1]
+ WHERE [t1].[row] <= COALESCE((
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+ ORDER BY [n].[value]
+ OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0)
+) AS [t0] ON [t].[FullName] = [t0].[OwnerFullName]
+ORDER BY [t].[Nickname], [t].[SquadId], [t0].[OwnerFullName], [t0].[Id]
+""");
+ }
+
+ public override async Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Skip_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_ElementAt_correlated_to_source(async);
+
+ AssertSql();
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
index a12560dd9dd..bbc6385fe39 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
@@ -11508,6 +11508,114 @@ GROUP BY [s].[Name]
""");
}
+ public override async Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[1,-1]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE
+ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
+END AS [Discriminator]
+FROM [Gears] AS [g]
+LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
+WHERE CASE
+ WHEN EXISTS (
+ SELECT 1
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]) THEN 1
+ ELSE 0
+END IN (
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+)
+""");
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__weapons_0='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE
+ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer'
+END AS [Discriminator]
+FROM [Gears] AS [g]
+LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId]
+WHERE EXISTS (
+ SELECT 1
+ FROM OPENJSON(@__weapons_0) WITH ([value] nvarchar(max) '$') AS [w0]
+ WHERE [w0].[value] = (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) OR ([w0].[value] IS NULL AND (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) IS NULL))
+""");
+ }
+
+ public override async Task Subquery_inside_Take_argument(bool async)
+ {
+ await base.Subquery_inside_Take_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[0,1,2]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId]
+FROM [Gears] AS [g]
+LEFT JOIN (
+ SELECT [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[SynergyWithId]
+ FROM (
+ SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row]
+ FROM [Weapons] AS [w]
+ ) AS [t]
+ WHERE [t].[row] <= COALESCE((
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+ ORDER BY [n].[value]
+ OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0)
+) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName]
+ORDER BY [g].[Nickname], [g].[SquadId], [t0].[OwnerFullName], [t0].[Id]
+""");
+ }
+
+ public override async Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Skip_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_ElementAt_correlated_to_source(async);
+
+ AssertSql();
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
index 590596a180d..c32b0178387 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
@@ -10059,6 +10059,108 @@ GROUP BY [s].[Name]
""");
}
+ public override async Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[1,-1]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
+FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
+WHERE CASE
+ WHEN EXISTS (
+ SELECT 1
+ FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]) THEN 1
+ ELSE 0
+END IN (
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+)
+""");
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__weapons_0='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank]
+FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
+WHERE EXISTS (
+ SELECT 1
+ FROM OPENJSON(@__weapons_0) WITH ([value] nvarchar(max) '$') AS [w0]
+ WHERE [w0].[value] = (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) OR ([w0].[value] IS NULL AND (
+ SELECT TOP(1) [w].[Name]
+ FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w]
+ WHERE [g].[FullName] = [w].[OwnerFullName]
+ ORDER BY [w].[Id]) IS NULL))
+""");
+ }
+
+ public override async Task Subquery_inside_Take_argument(bool async)
+ {
+ await base.Subquery_inside_Take_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[0,1,2]' (Size = 4000)
+
+SELECT [g].[Nickname], [g].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[SynergyWithId]
+FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g]
+LEFT JOIN (
+ SELECT [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[PeriodEnd], [t].[PeriodStart], [t].[SynergyWithId]
+ FROM (
+ SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[PeriodEnd], [w].[PeriodStart], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row]
+ FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w]
+ ) AS [t]
+ WHERE [t].[row] <= COALESCE((
+ SELECT [n].[value]
+ FROM OPENJSON(@__numbers_0) WITH ([value] int '$') AS [n]
+ ORDER BY [n].[value]
+ OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0)
+) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName]
+ORDER BY [g].[Nickname], [g].[SquadId], [t0].[OwnerFullName], [t0].[Id]
+""");
+ }
+
+ public override async Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Skip_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_ElementAt_correlated_to_source(async);
+
+ AssertSql();
+ }
+
private void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
index 2cb6e0ac610..1315218c721 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
@@ -9520,6 +9520,110 @@ GROUP BY "s"."Name"
""");
}
+ public override async Task Nav_expansion_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[1,-1]' (Size = 6)
+
+SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
+FROM "Gears" AS "g"
+WHERE CASE
+ WHEN EXISTS (
+ SELECT 1
+ FROM "Weapons" AS "w"
+ WHERE "g"."FullName" = "w"."OwnerFullName") THEN 1
+ ELSE 0
+END IN (
+ SELECT "n"."value"
+ FROM json_each(@__numbers_0) AS "n"
+)
+""");
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_argument(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Contains_argument(async);
+
+ AssertSql(
+"""
+@__weapons_0='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 44)
+
+SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank"
+FROM "Gears" AS "g"
+WHERE EXISTS (
+ SELECT 1
+ FROM json_each(@__weapons_0) AS "w0"
+ WHERE "w0"."value" = (
+ SELECT "w"."Name"
+ FROM "Weapons" AS "w"
+ WHERE "g"."FullName" = "w"."OwnerFullName"
+ ORDER BY "w"."Id"
+ LIMIT 1) OR ("w0"."value" IS NULL AND (
+ SELECT "w"."Name"
+ FROM "Weapons" AS "w"
+ WHERE "g"."FullName" = "w"."OwnerFullName"
+ ORDER BY "w"."Id"
+ LIMIT 1) IS NULL))
+""");
+ }
+
+ public override async Task Subquery_inside_Take_argument(bool async)
+ {
+ await base.Subquery_inside_Take_argument(async);
+
+ AssertSql(
+"""
+@__numbers_0='[0,1,2]' (Size = 7)
+
+SELECT "g"."Nickname", "g"."SquadId", "t0"."Id", "t0"."AmmunitionType", "t0"."IsAutomatic", "t0"."Name", "t0"."OwnerFullName", "t0"."SynergyWithId"
+FROM "Gears" AS "g"
+LEFT JOIN (
+ SELECT "t"."Id", "t"."AmmunitionType", "t"."IsAutomatic", "t"."Name", "t"."OwnerFullName", "t"."SynergyWithId"
+ FROM (
+ SELECT "w"."Id", "w"."AmmunitionType", "w"."IsAutomatic", "w"."Name", "w"."OwnerFullName", "w"."SynergyWithId", ROW_NUMBER() OVER(PARTITION BY "w"."OwnerFullName" ORDER BY "w"."Id") AS "row"
+ FROM "Weapons" AS "w"
+ ) AS "t"
+ WHERE "t"."row" <= COALESCE((
+ SELECT "n"."value"
+ FROM json_each(@__numbers_0) AS "n"
+ ORDER BY "n"."value"
+ LIMIT 1 OFFSET 1), 0)
+) AS "t0" ON "g"."FullName" = "t0"."OwnerFullName"
+ORDER BY "g"."Nickname", "g"."SquadId", "t0"."OwnerFullName", "t0"."Id"
+""");
+ }
+
+ public override async Task Nav_expansion_inside_Skip_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Skip_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_with_member_pushdown_inside_Take_correlated_to_source(async);
+
+ AssertSql();
+ }
+
+ public override async Task Nav_expansion_inside_ElementAt_correlated_to_source(bool async)
+ {
+ await base.Nav_expansion_inside_ElementAt_correlated_to_source(async);
+
+ AssertSql();
+ }
+
public override Task DateTimeOffset_to_unix_time_milliseconds(bool async)
=> AssertTranslationFailed(() => base.DateTimeOffset_to_unix_time_milliseconds(async));