Skip to content

Commit cda7816

Browse files
authored
Introduce QueryParameterExpression (#35101)
Closes #35089
1 parent 89c8ad8 commit cda7816

File tree

39 files changed

+346
-358
lines changed

39 files changed

+346
-358
lines changed

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

+9-15
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,16 @@ public virtual Expression Translate(SelectExpression selectExpression, Expressio
114114
case ConstantExpression:
115115
return expression;
116116

117-
case ParameterExpression parameterExpression:
118-
if (_collectionShaperMapping.ContainsKey(parameterExpression))
119-
{
120-
return parameterExpression;
121-
}
122-
123-
if (parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal)
124-
== true)
125-
{
126-
return Expression.Call(
127-
GetParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
128-
QueryCompilationContext.QueryContextParameter,
129-
Expression.Constant(parameterExpression.Name));
130-
}
117+
case QueryParameterExpression queryParameter:
118+
return Expression.Call(
119+
GetParameterValueMethodInfo.MakeGenericMethod(queryParameter.Type),
120+
QueryCompilationContext.QueryContextParameter,
121+
Expression.Constant(queryParameter.Name));
131122

132-
throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
123+
case ParameterExpression parameterExpression:
124+
return _collectionShaperMapping.ContainsKey(parameterExpression)
125+
? parameterExpression
126+
: throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
133127

134128
case MaterializeCollectionNavigationExpression:
135129
return base.Visit(expression);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ protected override bool ShouldConvertToInlineQueryRoot(Expression expression)
3838
/// any release. You should only use it directly in your code with extreme caution and knowing that
3939
/// doing so can result in application failures when updating to a new Entity Framework Core release.
4040
/// </summary>
41-
protected override bool ShouldConvertToParameterQueryRoot(ParameterExpression parameterExpression)
41+
protected override bool ShouldConvertToParameterQueryRoot(QueryParameterExpression parameterExpression)
4242
=> true;
4343

4444
/// <inheritdoc />

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression)
383383

384384
switch (fromSqlExpression.Arguments)
385385
{
386-
case ParameterExpression { Name: not null } parameterExpression
387-
when _parameterValues.TryGetValue(parameterExpression.Name, out var parameterValue)
386+
case QueryParameterExpression queryParameter
387+
when _parameterValues.TryGetValue(queryParameter.Name, out var parameterValue)
388388
&& parameterValue is object[] parameterValues:
389389
{
390390
substitutions = new string[parameterValues.Length];

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

+5-9
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ public override Expression Translate(Expression expression)
122122
if (arguments is not
123123
[
124124
_, // source
125-
ParameterExpression maxItemCount,
126-
ParameterExpression continuationToken,
127-
ParameterExpression responseContinuationTokenLimitInKb,
125+
QueryParameterExpression maxItemCount,
126+
QueryParameterExpression continuationToken,
127+
QueryParameterExpression responseContinuationTokenLimitInKb,
128128
_ // cancellation token
129129
]
130130
|| _sqlTranslator.Translate(maxItemCount) is not SqlParameterExpression translatedMaxItemCount
@@ -1496,18 +1496,14 @@ protected override ShapedQueryExpression TranslateSelect(ShapedQueryExpression s
14961496
/// </summary>
14971497
protected override ShapedQueryExpression? TranslateParameterQueryRoot(ParameterQueryRootExpression parameterQueryRootExpression)
14981498
{
1499-
var parameter = parameterQueryRootExpression.ParameterExpression;
1500-
if (parameter.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) != true)
1501-
{
1502-
return null;
1503-
}
1499+
var queryParameter = parameterQueryRootExpression.QueryParameterExpression;
15041500

15051501
// TODO: Temporary hack - need to perform proper derivation of the array type mapping from the element (e.g. for
15061502
// value conversion). #34026.
15071503
var elementClrType = parameterQueryRootExpression.ElementType;
15081504
var arrayTypeMapping = _typeMappingSource.FindMapping(typeof(IEnumerable<>).MakeGenericType(elementClrType));
15091505
var elementTypeMapping = _typeMappingSource.FindMapping(elementClrType)!;
1510-
var sqlParameterExpression = new SqlParameterExpression(parameter.Name, parameter.Type, arrayTypeMapping);
1506+
var sqlParameterExpression = new SqlParameterExpression(queryParameter.Name, queryParameter.Type, arrayTypeMapping);
15111507

15121508
var sourceAlias = _aliasManager.GenerateSourceAlias(sqlParameterExpression.Name.TrimStart('_'));
15131509
var select = SelectExpression.CreateForCollection(

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

+6-7
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ protected override Expression VisitExtension(Expression extensionExpression)
344344
case SqlExpression:
345345
return extensionExpression;
346346

347+
case QueryParameterExpression queryParameter:
348+
return new SqlParameterExpression(queryParameter.Name, queryParameter.Type, null);
349+
347350
case StructuralTypeShaperExpression shaper:
348351
return new EntityReferenceExpression(shaper);
349352

@@ -787,9 +790,7 @@ protected override Expression VisitNewArray(NewArrayExpression newArrayExpressio
787790
/// doing so can result in application failures when updating to a new Entity Framework Core release.
788791
/// </summary>
789792
protected override Expression VisitParameter(ParameterExpression parameterExpression)
790-
=> parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) == true
791-
? new SqlParameterExpression(parameterExpression.Name, parameterExpression.Type, null)
792-
: QueryCompilationContext.NotTranslatedExpression;
793+
=> QueryCompilationContext.NotTranslatedExpression;
793794

794795
/// <summary>
795796
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -1029,8 +1030,7 @@ private bool TryRewriteContainsEntity(Expression source, Expression item, [NotNu
10291030
rewrittenSource = Expression.Constant(propertyValueList);
10301031
break;
10311032

1032-
case SqlParameterExpression sqlParameterExpression
1033-
when sqlParameterExpression.Name.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal):
1033+
case SqlParameterExpression sqlParameterExpression:
10341034
var lambda = Expression.Lambda(
10351035
Expression.Call(
10361036
ParameterListValueExtractorMethod.MakeGenericMethod(entityType.ClrType, property.ClrType.MakeNullable()),
@@ -1156,8 +1156,7 @@ private Expression CreatePropertyAccessExpression(Expression target, IProperty p
11561156
return Expression.Constant(
11571157
property.GetGetter().GetClrValue(sqlConstantExpression.Value!), property.ClrType.MakeNullable());
11581158

1159-
case SqlParameterExpression sqlParameterExpression
1160-
when sqlParameterExpression.Name.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal):
1159+
case SqlParameterExpression sqlParameterExpression:
11611160
var lambda = Expression.Lambda(
11621161
Expression.Call(
11631162
ParameterValueExtractorMethod.MakeGenericMethod(property.ClrType.MakeNullable()),

src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs

+16-25
Original file line numberDiff line numberDiff line change
@@ -479,24 +479,25 @@ protected override Expression VisitConditional(ConditionalExpression conditional
479479
/// doing so can result in application failures when updating to a new Entity Framework Core release.
480480
/// </summary>
481481
protected override Expression VisitExtension(Expression extensionExpression)
482-
{
483-
switch (extensionExpression)
482+
=> extensionExpression switch
484483
{
485-
case EntityProjectionExpression:
486-
case StructuralTypeReferenceExpression:
487-
return extensionExpression;
484+
EntityProjectionExpression or StructuralTypeReferenceExpression
485+
=> extensionExpression,
488486

489-
case StructuralTypeShaperExpression shaper:
490-
return new StructuralTypeReferenceExpression(shaper);
487+
QueryParameterExpression queryParameter
488+
=> Expression.Call(
489+
GetParameterValueMethodInfo.MakeGenericMethod(queryParameter.Type),
490+
QueryCompilationContext.QueryContextParameter,
491+
Expression.Constant(queryParameter.Name)),
491492

492-
case ProjectionBindingExpression projectionBindingExpression:
493-
return ((InMemoryQueryExpression)projectionBindingExpression.QueryExpression)
494-
.GetProjection(projectionBindingExpression);
493+
StructuralTypeShaperExpression shaper
494+
=> new StructuralTypeReferenceExpression(shaper),
495495

496-
default:
497-
return QueryCompilationContext.NotTranslatedExpression;
498-
}
499-
}
496+
ProjectionBindingExpression projectionBindingExpression
497+
=> ((InMemoryQueryExpression)projectionBindingExpression.QueryExpression).GetProjection(projectionBindingExpression),
498+
499+
_ => QueryCompilationContext.NotTranslatedExpression
500+
};
500501

501502
/// <summary>
502503
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -988,17 +989,7 @@ protected override Expression VisitNewArray(NewArrayExpression newArrayExpressio
988989
/// doing so can result in application failures when updating to a new Entity Framework Core release.
989990
/// </summary>
990991
protected override Expression VisitParameter(ParameterExpression parameterExpression)
991-
{
992-
if (parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) == true)
993-
{
994-
return Expression.Call(
995-
GetParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
996-
QueryCompilationContext.QueryContextParameter,
997-
Expression.Constant(parameterExpression.Name));
998-
}
999-
1000-
throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
1001-
}
992+
=> throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
1002993

1003994
/// <summary>
1004995
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

src/EFCore.Relational/Query/Internal/FromSqlParameterExpandingExpressionVisitor.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ public virtual Expression Expand(
9292

9393
switch (fromSql.Arguments)
9494
{
95-
case ParameterExpression parameterExpression:
95+
case QueryParameterExpression queryParameter:
9696
// parameter value will never be null. It could be empty object?[]
97-
var parameterValues = (object?[])_parametersValues[parameterExpression.Name!]!;
97+
var parameterValues = (object?[])_parametersValues[queryParameter.Name]!;
9898
_canCache = false;
9999

100100
var subParameters = new List<IRelationalParameter>(parameterValues.Length);
@@ -127,7 +127,7 @@ public virtual Expression Expand(
127127
}
128128

129129
return _visitedFromSqlExpressions[fromSql] = fromSql.Update(
130-
Expression.Constant(new CompositeRelationalParameter(parameterExpression.Name!, subParameters)));
130+
Expression.Constant(new CompositeRelationalParameter(queryParameter.Name!, subParameters)));
131131

132132
case ConstantExpression { Value: object?[] existingValues }:
133133
{
@@ -158,7 +158,7 @@ public virtual Expression Expand(
158158
}
159159

160160
default:
161-
Check.DebugFail("FromSql.Arguments must be Constant/ParameterExpression");
161+
Check.DebugFail("FromSql.Arguments must be Constant/QueryParameterExpression");
162162
return null;
163163
}
164164

src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@ public RelationalCommandCache(
3434
IQuerySqlGeneratorFactory querySqlGeneratorFactory,
3535
IRelationalParameterBasedSqlProcessorFactory relationalParameterBasedSqlProcessorFactory,
3636
Expression queryExpression,
37-
bool useRelationalNulls,
38-
IReadOnlySet<string> parametersToConstantize)
37+
bool useRelationalNulls)
3938
{
4039
_memoryCache = memoryCache;
4140
_querySqlGeneratorFactory = querySqlGeneratorFactory;
4241
_queryExpression = queryExpression;
4342
_relationalParameterBasedSqlProcessor = relationalParameterBasedSqlProcessorFactory.Create(
44-
new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, parametersToConstantize));
43+
new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls));
4544
}
4645

4746
/// <summary>

src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ public virtual Expression Translate(SelectExpression selectExpression, Expressio
111111
case ConstantExpression:
112112
return expression;
113113

114+
case QueryParameterExpression queryParameterExpression:
115+
return Expression.Call(
116+
GetParameterValueMethodInfo.MakeGenericMethod(queryParameterExpression.Type),
117+
QueryCompilationContext.QueryContextParameter,
118+
Expression.Constant(queryParameterExpression.Name));
119+
114120
case ParameterExpression parameterExpression:
115-
return parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal)
116-
== true
117-
? Expression.Call(
118-
GetParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
119-
QueryCompilationContext.QueryContextParameter,
120-
Expression.Constant(parameterExpression.Name))
121-
: throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
121+
throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));
122122

123123
case ProjectionBindingExpression projectionBindingExpression:
124124
return _selectExpression.GetProjection(projectionBindingExpression) switch

src/EFCore.Relational/Query/Internal/RelationalQueryCompilationContextFactory.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ public virtual QueryCompilationContext Create(bool async)
5353
/// doing so can result in application failures when updating to a new Entity Framework Core release.
5454
/// </summary>
5555
[Experimental(EFDiagnostics.PrecompiledQueryExperimental)]
56-
public virtual QueryCompilationContext CreatePrecompiled(bool async, IReadOnlySet<string> nonNullableReferenceTypeParameters)
57-
=> new RelationalQueryCompilationContext(
58-
Dependencies, RelationalDependencies, async, precompiling: true, nonNullableReferenceTypeParameters);
56+
public virtual QueryCompilationContext CreatePrecompiled(bool async)
57+
=> new RelationalQueryCompilationContext(Dependencies, RelationalDependencies, async, precompiling: true);
5958
}

src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs

+2-11
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,11 @@ public sealed record RelationalParameterBasedSqlProcessorParameters
1313
/// </summary>
1414
public bool UseRelationalNulls { get; init; }
1515

16-
/// <summary>
17-
/// A collection of parameter names to constantize.
18-
/// </summary>
19-
public IReadOnlySet<string> ParametersToConstantize { get; init; }
20-
2116
/// <summary>
2217
/// Creates a new instance of <see cref="RelationalParameterBasedSqlProcessorParameters" />.
2318
/// </summary>
2419
/// <param name="useRelationalNulls">A value indicating if relational nulls should be used.</param>
25-
/// <param name="parametersToConstantize">A collection of parameter names to constantize.</param>
2620
[EntityFrameworkInternal]
27-
public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, IReadOnlySet<string> parametersToConstantize)
28-
{
29-
UseRelationalNulls = useRelationalNulls;
30-
ParametersToConstantize = parametersToConstantize;
31-
}
21+
public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls)
22+
=> UseRelationalNulls = useRelationalNulls;
3223
}

src/EFCore.Relational/Query/RelationalQueryCompilationContext.cs

+3-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public RelationalQueryCompilationContext(
2626
QueryCompilationContextDependencies dependencies,
2727
RelationalQueryCompilationContextDependencies relationalDependencies,
2828
bool async)
29-
: this(dependencies, relationalDependencies, async, precompiling: false, nonNullableReferenceTypeParameters: null)
29+
: this(dependencies, relationalDependencies, async, precompiling: false)
3030
{
3131
}
3232

@@ -37,15 +37,13 @@ public RelationalQueryCompilationContext(
3737
/// <param name="relationalDependencies">Parameter object containing relational dependencies for this class.</param>
3838
/// <param name="async">A bool value indicating whether it is for async query.</param>
3939
/// <param name="precompiling">Indicates whether the query is being precompiled.</param>
40-
/// <param name="nonNullableReferenceTypeParameters">Names of parameters which have non-nullable reference types.</param>
4140
[Experimental(EFDiagnostics.PrecompiledQueryExperimental)]
4241
public RelationalQueryCompilationContext(
4342
QueryCompilationContextDependencies dependencies,
4443
RelationalQueryCompilationContextDependencies relationalDependencies,
4544
bool async,
46-
bool precompiling,
47-
IReadOnlySet<string>? nonNullableReferenceTypeParameters)
48-
: base(dependencies, async, precompiling, nonNullableReferenceTypeParameters)
45+
bool precompiling)
46+
: base(dependencies, async, precompiling)
4947
{
5048
RelationalDependencies = relationalDependencies;
5149
QuerySplittingBehavior = RelationalOptionsExtension.Extract(ContextOptions).QuerySplittingBehavior;

src/EFCore.Relational/Query/RelationalQueryRootProcessor.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ protected override bool ShouldConvertToInlineQueryRoot(Expression expression)
3333
=> true;
3434

3535
/// <summary>
36-
/// Indicates that a <see cref="ParameterExpression" /> can be converted to a <see cref="ParameterQueryRootExpression" />;
36+
/// Indicates that a <see cref="QueryParameterExpression" /> can be converted to a <see cref="ParameterQueryRootExpression" />;
3737
/// the latter will end up in <see cref="RelationalQueryableMethodTranslatingExpressionVisitor.TranslatePrimitiveCollection" /> for
3838
/// translation to a provider-specific SQL expansion mechanism, e.g. <c>OPENJSON</c> on SQL Server.
3939
/// </summary>
40-
protected override bool ShouldConvertToParameterQueryRoot(ParameterExpression parameterExpression)
40+
protected override bool ShouldConvertToParameterQueryRoot(QueryParameterExpression queryParameterExpression)
4141
=> true;
4242

4343
/// <inheritdoc />

0 commit comments

Comments
 (0)