Skip to content

Commit ab7f83c

Browse files
committed
stub
1 parent 527e8b5 commit ab7f83c

26 files changed

+2023
-913
lines changed

Diff for: src/EFCore.InMemory/Query/Internal/EntityProjectionExpression.cs

+25
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,31 @@ public virtual void AddNavigationBinding(INavigation navigation, EntityShaperExp
148148
: null;
149149
}
150150

151+
/// <summary>
152+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
153+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
154+
/// any release. You should only use it directly in your code with extreme caution and knowing that
155+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
156+
/// </summary>
157+
public virtual EntityProjectionExpression Clone()
158+
{
159+
var readExpressionMap = new Dictionary<IProperty, MethodCallExpression>();
160+
foreach (var kvp in _readExpressionMap)
161+
{
162+
readExpressionMap.Add(kvp.Key, kvp.Value);
163+
}
164+
var entityProjectionExpression = new EntityProjectionExpression(EntityType, readExpressionMap);
165+
foreach (var kvp in _navigationExpressionsCache)
166+
{
167+
entityProjectionExpression._navigationExpressionsCache[kvp.Key] = new EntityShaperExpression(
168+
kvp.Value.EntityType,
169+
((EntityProjectionExpression)kvp.Value.ValueBufferExpression).Clone(),
170+
kvp.Value.IsNullable);
171+
}
172+
173+
return entityProjectionExpression;
174+
}
175+
151176
/// <summary>
152177
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
153178
/// the same compatibility standards as public APIs. It may be changed or removed without notice in

Diff for: src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs

+8-290
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,50 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Linq.Expressions;
5-
using Microsoft.EntityFrameworkCore.Query;
4+
//using System.Linq.Expressions;
5+
//using Microsoft.EntityFrameworkCore.Query;
66

7-
namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal
8-
{
9-
/// <summary>
10-
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
11-
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
12-
/// any release. You should only use it directly in your code with extreme caution and knowing that
13-
/// doing so can result in application failures when updating to a new Entity Framework Core release.
14-
/// </summary>
15-
public class InMemoryGroupByShaperExpression : GroupByShaperExpression
16-
{
17-
/// <summary>
18-
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
19-
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
20-
/// any release. You should only use it directly in your code with extreme caution and knowing that
21-
/// doing so can result in application failures when updating to a new Entity Framework Core release.
22-
/// </summary>
23-
public InMemoryGroupByShaperExpression(
24-
Expression keySelector,
25-
Expression elementSelector,
26-
ParameterExpression groupingParameter,
27-
ParameterExpression valueBufferParameter)
28-
: base(keySelector, elementSelector)
29-
{
30-
GroupingParameter = groupingParameter;
31-
ValueBufferParameter = valueBufferParameter;
32-
}
7+
//namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal
8+
//{
9+
// /// <summary>
10+
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
11+
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
12+
// /// any release. You should only use it directly in your code with extreme caution and knowing that
13+
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
14+
// /// </summary>
15+
// public class InMemoryGroupByShaperExpression : GroupByShaperExpression
16+
// {
17+
// /// <summary>
18+
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
19+
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
20+
// /// any release. You should only use it directly in your code with extreme caution and knowing that
21+
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
22+
// /// </summary>
23+
// public InMemoryGroupByShaperExpression(
24+
// Expression keySelector,
25+
// Expression elementSelector,
26+
// ParameterExpression groupingParameter,
27+
// ParameterExpression valueBufferParameter)
28+
// : base(keySelector, elementSelector)
29+
// {
30+
// GroupingParameter = groupingParameter;
31+
// ValueBufferParameter = valueBufferParameter;
32+
// }
3333

34-
/// <summary>
35-
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
36-
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
37-
/// any release. You should only use it directly in your code with extreme caution and knowing that
38-
/// doing so can result in application failures when updating to a new Entity Framework Core release.
39-
/// </summary>
40-
public virtual ParameterExpression GroupingParameter { get; }
34+
// /// <summary>
35+
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
36+
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
37+
// /// any release. You should only use it directly in your code with extreme caution and knowing that
38+
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
39+
// /// </summary>
40+
// public virtual ParameterExpression GroupingParameter { get; }
4141

42-
/// <summary>
43-
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
44-
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
45-
/// any release. You should only use it directly in your code with extreme caution and knowing that
46-
/// doing so can result in application failures when updating to a new Entity Framework Core release.
47-
/// </summary>
48-
public virtual ParameterExpression ValueBufferParameter { get; }
49-
}
50-
}
42+
// /// <summary>
43+
// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
44+
// /// the same compatibility standards as public APIs. It may be changed or removed without notice in
45+
// /// any release. You should only use it directly in your code with extreme caution and knowing that
46+
// /// doing so can result in application failures when updating to a new Entity Framework Core release.
47+
// /// </summary>
48+
// public virtual ParameterExpression ValueBufferParameter { get; }
49+
// }
50+
//}

Diff for: src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.Helper.cs

+60
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Collections.Generic;
77
using System.Diagnostics.CodeAnalysis;
88
using System.Linq.Expressions;
9+
using Microsoft.EntityFrameworkCore.Metadata;
910
using Microsoft.EntityFrameworkCore.Query;
1011
using Microsoft.EntityFrameworkCore.Storage;
1112
using Microsoft.EntityFrameworkCore.Utilities;
@@ -173,5 +174,64 @@ protected override Expression VisitExtension(Expression extensionExpression)
173174
: base.VisitExtension(extensionExpression);
174175
}
175176
}
177+
178+
private sealed class QueryExpressionReplacingExpressionVisitor : ExpressionVisitor
179+
{
180+
private readonly Expression _oldQuery;
181+
private readonly Expression _newQuery;
182+
183+
public QueryExpressionReplacingExpressionVisitor(Expression oldQuery, Expression newQuery)
184+
{
185+
_oldQuery = oldQuery;
186+
_newQuery = newQuery;
187+
}
188+
189+
[return: NotNullIfNotNull("expression")]
190+
public override Expression? Visit(Expression? expression)
191+
{
192+
return expression is ProjectionBindingExpression projectionBindingExpression
193+
&& ReferenceEquals(projectionBindingExpression.QueryExpression, _oldQuery)
194+
? projectionBindingExpression.ProjectionMember != null
195+
? new ProjectionBindingExpression(
196+
_newQuery, projectionBindingExpression.ProjectionMember!, projectionBindingExpression.Type)
197+
: new ProjectionBindingExpression(
198+
_newQuery, projectionBindingExpression.Index!.Value, projectionBindingExpression.Type)
199+
: base.Visit(expression);
200+
}
201+
}
202+
203+
private sealed class CloningExpressionVisitor : ExpressionVisitor
204+
{
205+
[return: NotNullIfNotNull("expression")]
206+
public override Expression? Visit(Expression? expression)
207+
{
208+
if (expression is InMemoryQueryExpression inMemoryQueryExpression)
209+
{
210+
var clonedInMemoryQueryExpression = new InMemoryQueryExpression(
211+
inMemoryQueryExpression.ServerQueryExpression, inMemoryQueryExpression._valueBufferParameter)
212+
{
213+
_groupingParameter = inMemoryQueryExpression._groupingParameter,
214+
_singleResultMethodInfo = inMemoryQueryExpression._singleResultMethodInfo,
215+
_scalarServerQuery = inMemoryQueryExpression._scalarServerQuery
216+
};
217+
218+
clonedInMemoryQueryExpression._clientProjections.AddRange(inMemoryQueryExpression._clientProjections.Select(e => Visit(e)));
219+
clonedInMemoryQueryExpression._projectionMappingExpressions.AddRange(inMemoryQueryExpression._projectionMappingExpressions);
220+
foreach (var item in inMemoryQueryExpression._projectionMapping)
221+
{
222+
clonedInMemoryQueryExpression._projectionMapping[item.Key] = Visit(item.Value);
223+
}
224+
225+
return clonedInMemoryQueryExpression;
226+
}
227+
228+
if (expression is EntityProjectionExpression entityProjectionExpression)
229+
{
230+
return entityProjectionExpression.Clone();
231+
}
232+
233+
return base.Visit(expression);
234+
}
235+
}
176236
}
177237
}

Diff for: src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs

+50-8
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,20 @@ private static readonly ConstructorInfo _resultEnumerableConstructor
4141
private MethodInfo? _singleResultMethodInfo;
4242
private bool _scalarServerQuery;
4343

44+
private CloningExpressionVisitor? _cloningExpressionVisitor;
45+
4446
private Dictionary<ProjectionMember, Expression> _projectionMapping = new();
4547
private readonly List<Expression> _clientProjections = new();
4648
private readonly List<Expression> _projectionMappingExpressions = new();
4749

50+
private InMemoryQueryExpression(
51+
Expression serverQueryExpression,
52+
ParameterExpression valueBufferParameter)
53+
{
54+
ServerQueryExpression = serverQueryExpression;
55+
_valueBufferParameter = valueBufferParameter;
56+
}
57+
4858
/// <summary>
4959
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
5060
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -333,15 +343,17 @@ public virtual void ApplyProjection()
333343
ServerQueryExpression,
334344
selectorLambda);
335345

346+
_groupingParameter = null;
347+
336348
if (_singleResultMethodInfo != null)
337349
{
338350
ServerQueryExpression = Call(
339351
_singleResultMethodInfo.MakeGenericMethod(CurrentParameter.Type),
340352
ServerQueryExpression);
341353

342-
_singleResultMethodInfo = null;
343-
344354
ConvertToEnumerable();
355+
356+
_singleResultMethodInfo = null;
345357
}
346358
}
347359

@@ -540,7 +552,7 @@ public virtual void ApplyDistinct()
540552
/// any release. You should only use it directly in your code with extreme caution and knowing that
541553
/// doing so can result in application failures when updating to a new Entity Framework Core release.
542554
/// </summary>
543-
public virtual InMemoryGroupByShaperExpression ApplyGrouping(
555+
public virtual GroupByShaperExpression ApplyGrouping(
544556
Expression groupingKey,
545557
Expression shaperExpression,
546558
bool defaultElementSelector)
@@ -583,11 +595,15 @@ public virtual InMemoryGroupByShaperExpression ApplyGrouping(
583595
keySelector,
584596
selector);
585597

586-
return new InMemoryGroupByShaperExpression(
598+
var clonedInMemoryQueryExpression = Clone();
599+
clonedInMemoryQueryExpression.UpdateServerQueryExpression(_groupingParameter);
600+
clonedInMemoryQueryExpression._groupingParameter = null;
601+
602+
return new GroupByShaperExpression(
587603
groupingKey,
588-
shaperExpression,
589-
_groupingParameter,
590-
_valueBufferParameter);
604+
new ShapedQueryExpression(
605+
clonedInMemoryQueryExpression,
606+
new QueryExpressionReplacingExpressionVisitor(this, clonedInMemoryQueryExpression).Visit(shaperExpression)));
591607
}
592608

593609
/// <summary>
@@ -711,6 +727,22 @@ public virtual EntityShaperExpression AddNavigationToWeakEntityType(
711727
return entityShaper;
712728
}
713729

730+
/// <summary>
731+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
732+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
733+
/// any release. You should only use it directly in your code with extreme caution and knowing that
734+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
735+
/// </summary>
736+
public virtual ShapedQueryExpression Clone(Expression shaperExpression)
737+
{
738+
var clonedInMemoryQueryExpression = Clone();
739+
740+
return new ShapedQueryExpression(
741+
clonedInMemoryQueryExpression,
742+
new QueryExpressionReplacingExpressionVisitor(this, clonedInMemoryQueryExpression).Visit(shaperExpression));
743+
744+
}
745+
714746
/// <summary>
715747
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
716748
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -811,6 +843,16 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
811843
}
812844
}
813845

846+
private InMemoryQueryExpression Clone()
847+
{
848+
if (_cloningExpressionVisitor == null)
849+
{
850+
_cloningExpressionVisitor = new();
851+
}
852+
853+
return (InMemoryQueryExpression)_cloningExpressionVisitor.Visit(this);
854+
}
855+
814856
private Expression GetGroupingKey(Expression key, List<Expression> groupingExpressions, Expression groupingKeyAccessExpression)
815857
{
816858
switch (key)
@@ -1061,7 +1103,7 @@ static Expression MakeNullable(Expression expression, bool nullable)
10611103

10621104
private void ConvertToEnumerable()
10631105
{
1064-
if (ServerQueryExpression.Type.TryGetSequenceType() == null)
1106+
if (_scalarServerQuery || _singleResultMethodInfo != null)
10651107
{
10661108
if (ServerQueryExpression.Type != typeof(ValueBuffer))
10671109
{

Diff for: src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs

+21-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78
using System.Linq.Expressions;
89
using System.Reflection;
@@ -70,6 +71,24 @@ protected InMemoryQueryableMethodTranslatingExpressionVisitor(
7071
protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVisitor()
7172
=> new InMemoryQueryableMethodTranslatingExpressionVisitor(this);
7273

74+
/// <summary>
75+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
76+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
77+
/// any release. You should only use it directly in your code with extreme caution and knowing that
78+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
79+
/// </summary>
80+
protected override Expression VisitExtension(Expression extensionExpression)
81+
{
82+
if (extensionExpression is GroupByShaperExpression groupByShaperExpression)
83+
{
84+
var shapedQueryExpression = groupByShaperExpression.GroupingEnumerable;
85+
return ((InMemoryQueryExpression)shapedQueryExpression.QueryExpression)
86+
.Clone(shapedQueryExpression.ShaperExpression);
87+
}
88+
89+
return base.VisitExtension(extensionExpression);
90+
}
91+
7392
/// <summary>
7493
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
7594
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -1513,7 +1532,8 @@ private static Expression AccessField(
15131532
inMemoryQueryExpression.CurrentParameter)
15141533
: TranslateLambdaExpression(source, selector, preserveType: true);
15151534

1516-
if (selector == null)
1535+
if (selector == null
1536+
|| selector.Body is EntityProjectionExpression)
15171537
{
15181538
return null;
15191539
}

0 commit comments

Comments
 (0)