Skip to content

Commit 698ed42

Browse files
committed
Query:
Resolves #18140 Resolves #18374 Resolves #18672 Resolves #18734 Resolves #19138 Resolves #19207
1 parent d5ead04 commit 698ed42

23 files changed

+751
-341
lines changed

src/EFCore.Cosmos/Query/Internal/QuerySqlGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ protected override Expression VisitSelect(SelectExpression selectExpression)
247247
}
248248
else
249249
{
250-
throw new InvalidOperationException(CoreStrings.QueryFailed(selectExpression.Print(), GetType().Name));
250+
// TODO: See Issue#18923
251+
throw new InvalidOperationException("Cosmos Sql API does not support Offset without Limit.");
251252
}
252253
}
253254

src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,8 @@ protected Expression ExpandNavigation(
246246

247247
var outerKeySelector = _navigationExpandingExpressionVisitor.GenerateLambda(
248248
outerKey, _source.CurrentParameter);
249-
var innerKeySelector = _navigationExpandingExpressionVisitor.GenerateLambda(
250-
_navigationExpandingExpressionVisitor.ExpandNavigationsInLambdaExpression(
251-
innerSource,
252-
Expression.Lambda(innerKey, innerParameter)),
253-
innerSource.CurrentParameter);
249+
var innerKeySelector = _navigationExpandingExpressionVisitor.ProcessLambdaExpression(
250+
innerSource, Expression.Lambda(innerKey, innerParameter));
254251

255252
var resultSelectorOuterParameter = Expression.Parameter(_source.SourceElementType, "o");
256253
var resultSelectorInnerParameter = Expression.Parameter(innerSource.SourceElementType, "i");
@@ -349,10 +346,22 @@ protected override Expression VisitMember(MemberExpression memberExpression)
349346
{
350347
Check.NotNull(memberExpression, nameof(memberExpression));
351348

352-
if (UnwrapEntityReference(memberExpression.Expression) is EntityReference entityReferece)
349+
var innerExpression = memberExpression.Expression.UnwrapTypeConversion(out var convertedType);
350+
if (UnwrapEntityReference(innerExpression) is EntityReference entityReference)
353351
{
354352
// If it is mapped property then, it would get converted to a column so we don't need to expand includes.
355-
var property = entityReferece.EntityType.FindProperty(memberExpression.Member);
353+
var entityType = entityReference.EntityType;
354+
if (convertedType != null)
355+
{
356+
entityType = entityType.GetTypesInHierarchy()
357+
.FirstOrDefault(et => et.ClrType == convertedType);
358+
if (entityType == null)
359+
{
360+
return base.VisitMember(memberExpression);
361+
}
362+
}
363+
364+
var property = entityType.FindProperty(memberExpression.Member);
356365
if (property != null)
357366
{
358367
return memberExpression;
@@ -366,7 +375,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
366375
{
367376
Check.NotNull(methodCallExpression, nameof(methodCallExpression));
368377

369-
if (methodCallExpression.TryGetEFPropertyArguments(out var _, out var __))
378+
if (methodCallExpression.TryGetEFPropertyArguments(out _, out _))
370379
{
371380
// If it is EF.Property then, it would get converted to a column or throw
372381
// so we don't need to expand includes.

src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
using System.Linq;
77
using System.Linq.Expressions;
88
using System.Reflection;
9-
using Microsoft.EntityFrameworkCore.Diagnostics;
10-
using Microsoft.EntityFrameworkCore.Infrastructure;
119
using Microsoft.EntityFrameworkCore.Metadata;
1210
using Microsoft.EntityFrameworkCore.Utilities;
1311

@@ -316,9 +314,6 @@ private set
316314
public virtual NavigationTreeNode Right { get; }
317315
public virtual ParameterExpression CurrentParameter { get; private set; }
318316

319-
protected override Expression VisitChildren(ExpressionVisitor visitor)
320-
=> throw new InvalidOperationException(CoreStrings.QueryFailed(this.Print(), GetType().Name));
321-
322317
public virtual void SetParameter(string parameterName) => CurrentParameter = Parameter(Type, parameterName);
323318

324319
public override ExpressionType NodeType => ExpressionType.Extension;

src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs

Lines changed: 120 additions & 163 deletions
Large diffs are not rendered by default.

src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
5656

5757
ShapedQueryExpression CheckTranslated(ShapedQueryExpression translated)
5858
{
59-
if (translated == null)
60-
{
61-
throw new InvalidOperationException(
62-
CoreStrings.TranslationFailed(methodCallExpression.Print()));
63-
}
64-
65-
return translated;
59+
return translated ?? throw new InvalidOperationException(CoreStrings.TranslationFailed(methodCallExpression.Print()));
6660
}
6761

6862
var method = methodCallExpression.Method;

src/Shared/EnumerableMethods.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace Microsoft.EntityFrameworkCore
1010
{
1111
internal static class EnumerableMethods
1212
{
13+
public static MethodInfo AsEnumerable { get; }
1314
public static MethodInfo Cast { get; }
1415
public static MethodInfo OfType { get; }
1516

@@ -130,6 +131,8 @@ static EnumerableMethods()
130131
.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
131132
.ToList();
132133

134+
AsEnumerable = enumerableMethods.Single(
135+
mi => mi.Name == nameof(Enumerable.AsEnumerable) && mi.IsGenericMethod && mi.GetParameters().Length == 1);
133136
Cast = enumerableMethods.Single(
134137
mi => mi.Name == nameof(Enumerable.Cast) && mi.GetParameters().Length == 1);
135138
OfType = enumerableMethods.Single(

src/Shared/ExpressionExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ public static Expression UnwrapTypeConversion(this Expression expression, out Ty
1818
{
1919
convertedType = null;
2020
while (expression is UnaryExpression unaryExpression
21-
&& unaryExpression.NodeType == ExpressionType.Convert)
21+
&& (unaryExpression.NodeType == ExpressionType.Convert
22+
|| unaryExpression.NodeType == ExpressionType.ConvertChecked
23+
|| unaryExpression.NodeType == ExpressionType.TypeAs))
2224
{
2325
expression = unaryExpression.Operand;
2426
if (unaryExpression.Type != typeof(object) // Ignore object conversion

test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3988,6 +3988,57 @@ public override Task Subquery_DefaultIfEmpty_Any(bool async)
39883988
return base.Subquery_DefaultIfEmpty_Any(async);
39893989
}
39903990

3991+
[ConditionalTheory(Skip = "Issue #17246")]
3992+
public override Task Projection_skip_collection_projection(bool async)
3993+
{
3994+
return base.Projection_skip_collection_projection(async);
3995+
}
3996+
3997+
[ConditionalTheory(Skip = "Issue #17246")]
3998+
public override Task Projection_take_collection_projection(bool async)
3999+
{
4000+
return base.Projection_take_collection_projection(async);
4001+
}
4002+
4003+
[ConditionalTheory(Skip = "Issue #17246")]
4004+
public override Task Projection_skip_take_collection_projection(bool async)
4005+
{
4006+
return base.Projection_skip_take_collection_projection(async);
4007+
}
4008+
4009+
public override Task Projection_skip_projection(bool async)
4010+
{
4011+
return AssertTranslationFailed(() => base.Projection_skip_projection(async));
4012+
}
4013+
4014+
public override Task Projection_take_projection(bool async)
4015+
{
4016+
return AssertTranslationFailed(() => base.Projection_take_projection(async));
4017+
}
4018+
4019+
public override Task Projection_skip_take_projection(bool async)
4020+
{
4021+
return AssertTranslationFailed(() => base.Projection_skip_take_projection(async));
4022+
}
4023+
4024+
[ConditionalTheory(Skip = "Issue #17246")]
4025+
public override Task Collection_projection_skip(bool async)
4026+
{
4027+
return base.Collection_projection_skip(async);
4028+
}
4029+
4030+
[ConditionalTheory(Skip = "Issue #17246")]
4031+
public override Task Collection_projection_take(bool async)
4032+
{
4033+
return base.Collection_projection_take(async);
4034+
}
4035+
4036+
[ConditionalTheory(Skip = "Issue #17246")]
4037+
public override Task Collection_projection_skip_take(bool async)
4038+
{
4039+
return base.Collection_projection_skip_take(async);
4040+
}
4041+
39914042
private void AssertSql(params string[] expected)
39924043
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
39934044

test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,18 @@ public override Task No_ignored_include_warning_when_implicit_load(bool async)
236236
return base.No_ignored_include_warning_when_implicit_load(async);
237237
}
238238

239+
[ConditionalTheory(Skip = "Skip withouth Take #18923")]
240+
public override Task Client_method_skip_loads_owned_navigations(bool async)
241+
{
242+
return base.Client_method_skip_loads_owned_navigations(async);
243+
}
244+
245+
[ConditionalTheory(Skip = "Skip withouth Take #18923")]
246+
public override Task Client_method_skip_loads_owned_navigations_variation_2(bool async)
247+
{
248+
return base.Client_method_skip_loads_owned_navigations_variation_2(async);
249+
}
250+
239251
private void AssertSql(params string[] expected)
240252
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
241253

test/EFCore.Relational.Specification.Tests/Query/QueryNoClientEvalTestBase.cs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -103,59 +103,34 @@ public virtual void Throws_when_subquery_main_from_clause()
103103
public virtual void Throws_when_select_many()
104104
{
105105
using var context = CreateContext();
106-
Assert.Equal(
107-
CoreStrings.QueryFailed(
108-
"c1 => int[] { 1, 2, 3, }",
109-
"NavigationExpandingExpressionVisitor"),
110-
Assert.Throws<InvalidOperationException>(
111-
() => (from c1 in context.Customers
112-
from i in new[] { 1, 2, 3 }
113-
select c1)
114-
.ToList()).Message);
106+
107+
AssertTranslationFailed(
108+
() => (from c1 in context.Customers
109+
from i in new[] { 1, 2, 3 }
110+
select c1)
111+
.ToList());
115112
}
116113

117114
[ConditionalFact]
118115
public virtual void Throws_when_join()
119116
{
120117
using var context = CreateContext();
121-
var message = Assert.Throws<InvalidOperationException>(
118+
AssertTranslationFailed(
122119
() => (from e1 in context.Employees
123120
join i in new uint[] { 1, 2, 3 } on e1.EmployeeID equals i
124121
select e1)
125-
.ToList()).Message;
126-
127-
Assert.Equal(
128-
CoreStrings.QueryFailed(
129-
@"DbSet<Employee>
130-
.Join(
131-
inner: __p_0,
132-
outerKeySelector: e1 => e1.EmployeeID,
133-
innerKeySelector: i => i,
134-
resultSelector: (e1, i) => e1)",
135-
"NavigationExpandingExpressionVisitor"),
136-
message, ignoreLineEndingDifferences: true);
122+
.ToList());
137123
}
138124

139125
[ConditionalFact]
140126
public virtual void Throws_when_group_join()
141127
{
142128
using var context = CreateContext();
143-
var message = Assert.Throws<InvalidOperationException>(
129+
AssertTranslationFailed(
144130
() => (from e1 in context.Employees
145131
join i in new uint[] { 1, 2, 3 } on e1.EmployeeID equals i into g
146132
select e1)
147-
.ToList()).Message;
148-
149-
Assert.Equal(
150-
CoreStrings.QueryFailed(
151-
@"DbSet<Employee>
152-
.GroupJoin(
153-
inner: __p_0,
154-
outerKeySelector: e1 => e1.EmployeeID,
155-
innerKeySelector: i => i,
156-
resultSelector: (e1, g) => e1)",
157-
"NavigationExpandingExpressionVisitor"),
158-
message, ignoreLineEndingDifferences: true);
133+
.ToList());
159134
}
160135

161136
[ConditionalFact(Skip = "Issue#18923")]

test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@ public virtual async Task Select_navigation_with_concat_and_count(bool async)
15591559
ss => ss.Set<Gear>().Where(g => !g.HasSoulPatch).Select(g => g.Weapons.Concat(g.Weapons).Count())))).Message;
15601560

15611561
Assert.Equal(
1562-
CoreStrings.QueryFailed(
1562+
CoreStrings.TranslationFailed(
15631563
@"(MaterializeCollectionNavigation(
15641564
navigation: Navigation: Gear.Weapons,
15651565
subquery: (NavigationExpansionExpression
@@ -1588,7 +1588,7 @@ public virtual async Task Select_navigation_with_concat_and_count(bool async)
15881588
Value: (EntityReference: Gear)
15891589
Expression: g), ""FullName"") != null && EF.Property<string>((NavigationTreeExpression
15901590
Value: (EntityReference: Gear)
1591-
Expression: g), ""FullName"") == EF.Property<string>(i, ""OwnerFullName""))))", "NavigationExpandingExpressionVisitor"),
1591+
Expression: g), ""FullName"") == EF.Property<string>(i, ""OwnerFullName""))))"),
15921592
message, ignoreLineEndingDifferences: true);
15931593
}
15941594

@@ -1602,7 +1602,7 @@ public virtual async Task Concat_with_collection_navigations(bool async)
16021602
ss => ss.Set<Gear>().Where(g => g.HasSoulPatch).Select(g => g.Weapons.Union(g.Weapons).Count())))).Message;
16031603

16041604
Assert.Equal(
1605-
CoreStrings.QueryFailed(
1605+
CoreStrings.TranslationFailed(
16061606
@"(MaterializeCollectionNavigation(
16071607
navigation: Navigation: Gear.Weapons,
16081608
subquery: (NavigationExpansionExpression
@@ -1631,7 +1631,7 @@ public virtual async Task Concat_with_collection_navigations(bool async)
16311631
Value: (EntityReference: Gear)
16321632
Expression: g), ""FullName"") != null && EF.Property<string>((NavigationTreeExpression
16331633
Value: (EntityReference: Gear)
1634-
Expression: g), ""FullName"") == EF.Property<string>(i, ""OwnerFullName""))))", "NavigationExpandingExpressionVisitor"),
1634+
Expression: g), ""FullName"") == EF.Property<string>(i, ""OwnerFullName""))))"),
16351635
message, ignoreLineEndingDifferences: true);
16361636
}
16371637

@@ -3106,19 +3106,15 @@ orderby FavoriteWeapon(g.Weapons).Name descending
31063106

31073107
[ConditionalTheory]
31083108
[MemberData(nameof(IsAsyncData))]
3109-
public virtual async Task Client_method_on_collection_navigation_in_additional_from_clause(bool async)
3109+
public virtual Task Client_method_on_collection_navigation_in_additional_from_clause(bool async)
31103110
{
3111-
var message = (await Assert.ThrowsAsync<InvalidOperationException>(
3111+
return AssertTranslationFailed(
31123112
() => AssertQuery(
31133113
async,
31143114
ss => from g in ss.Set<Gear>().OfType<Officer>()
31153115
from v in Veterans(g.Reports)
31163116
select new { g = g.Nickname, v = v.Nickname },
3117-
elementSorter: e => e.g + e.v))).Message;
3118-
3119-
Assert.StartsWith(
3120-
CoreStrings.QueryFailed("", "").Substring(0, 35),
3121-
message);
3117+
elementSorter: e => e.g + e.v));
31223118
}
31233119

31243120
[ConditionalTheory(Skip = "Issue #17328")]
@@ -7397,7 +7393,7 @@ public virtual Task OrderBy_bool_coming_from_optional_navigation(bool async)
73977393
ss => ss.Set<Weapon>().Select(w => w.SynergyWith).OrderBy(g => MaybeScalar<bool>(g, () => g.IsAutomatic)),
73987394
assertOrder: true);
73997395
}
7400-
7396+
74017397
[ConditionalFact]
74027398
public virtual void Byte_array_filter_by_length_parameter_compiled()
74037399
{

test/EFCore.Specification.Tests/Query/NorthwindIncludeQueryTestBase.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3518,6 +3518,31 @@ orderby e.EmployeeID
35183518
private static string ClientMethod(Employee e)
35193519
=> e.FirstName + " reports to " + e.Manager.FirstName + e.Manager.LastName;
35203520

3521+
// Issue#18672
3522+
[ConditionalTheory]
3523+
[InlineData(false, false)]
3524+
[InlineData(true, false)]
3525+
[InlineData(false, true)]
3526+
[InlineData(true, true)]
3527+
public virtual async Task Multi_level_includes_are_applied_with_skip(bool useString, bool async)
3528+
{
3529+
using var context = CreateContext();
3530+
var query = (from c in (useString
3531+
? context.Customers.Include("Orders.OrderDetails")
3532+
: context.Customers.Include(e => e.Orders).ThenInclude(e => e.OrderDetails))
3533+
where c.CustomerID.StartsWith("A")
3534+
orderby c.CustomerID
3535+
select new { c.CustomerID, Orders = c.Orders.ToList() })
3536+
.Skip(0);
3537+
3538+
var result = async
3539+
? await query.FirstAsync()
3540+
: query.First();
3541+
3542+
Assert.Equal("ALFKI", result.CustomerID);
3543+
Assert.Equal(3, result.Orders.First().OrderDetails.Count);
3544+
}
3545+
35213546
private static void CheckIsLoaded(
35223547
NorthwindContext context,
35233548
Customer customer,

0 commit comments

Comments
 (0)