Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/EFCore.Relational/EFExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;

namespace Microsoft.EntityFrameworkCore;

/// <summary>
Expand All @@ -25,10 +27,10 @@ public static class EFExtensions
/// Within the context of an EF LINQ query, forces its argument to be inserted into the query as a multiple parameter expressions.
/// </summary>
/// <remarks>Note that this is a static method accessed through the top-level <see cref="EF" /> static type.</remarks>
/// <typeparam name="T">The type of collection element.</typeparam>
/// <typeparam name="TSource">The type of collection.</typeparam>
/// <param name="argument">The collection to be integrated as parameters into the query.</param>
/// <returns>The same value for further use in the query.</returns>
public static IEnumerable<T> MultipleParameters<T>(IEnumerable<T> argument)
public static TSource MultipleParameters<TSource>(TSource argument) where TSource : IEnumerable
=> throw new InvalidOperationException(RelationalStrings.EFMultipleParametersInvoked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public virtual TBuilder ExecutionStrategy(
/// </remarks>
[Obsolete("Use UseParameterizedCollectionMode instead.")]
public virtual TBuilder TranslateParameterizedCollectionsToConstants()
=> UseParameterizedCollectionMode(ParameterizedCollectionMode.Constants);
=> UseParameterizedCollectionMode(ParameterTranslationMode.Constant);

/// <summary>
/// Configures the context to translate parameterized collections to a single array-like parameter.
Expand All @@ -202,13 +202,13 @@ public virtual TBuilder TranslateParameterizedCollectionsToConstants()
/// </remarks>
[Obsolete("Use UseParameterizedCollectionMode instead.")]
public virtual TBuilder TranslateParameterizedCollectionsToParameters()
=> UseParameterizedCollectionMode(ParameterizedCollectionMode.Parameter);
=> UseParameterizedCollectionMode(ParameterTranslationMode.Parameter);

/// <summary>
/// Configures the <see cref="ParameterizedCollectionMode" /> to use when translating parameterized collections.
/// Configures the mode to use when translating parameterized collections.
/// </summary>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public virtual TBuilder UseParameterizedCollectionMode(ParameterizedCollectionMode parameterizedCollectionMode)
public virtual TBuilder UseParameterizedCollectionMode(ParameterTranslationMode parameterizedCollectionMode)
=> WithOption(e => (TExtension)e.WithUseParameterizedCollectionMode(parameterizedCollectionMode));

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public abstract class RelationalOptionsExtension : IDbContextOptionsExtension
private string? _migrationsHistoryTableName;
private string? _migrationsHistoryTableSchema;
private Func<ExecutionStrategyDependencies, IExecutionStrategy>? _executionStrategyFactory;
private ParameterizedCollectionMode? _parameterizedCollectionMode;
private ParameterTranslationMode? _parameterizedCollectionMode;

/// <summary>
/// Creates a new set of options with everything set to default values.
Expand Down Expand Up @@ -386,16 +386,16 @@ public virtual RelationalOptionsExtension WithExecutionStrategyFactory(
/// <summary>
/// Configured translation mode for parameterized collections.
/// </summary>
public virtual ParameterizedCollectionMode ParameterizedCollectionMode
=> _parameterizedCollectionMode ?? ParameterizedCollectionMode.MultipleParameters;
public virtual ParameterTranslationMode ParameterizedCollectionMode
=> _parameterizedCollectionMode ?? ParameterTranslationMode.MultipleParameters;

/// <summary>
/// Creates a new instance with all options the same as for this instance, but with the given option changed.
/// It is unusual to call this method directly. Instead use <see cref="DbContextOptionsBuilder" />.
/// </summary>
/// <param name="parameterizedCollectionMode">The option to change.</param>
public virtual RelationalOptionsExtension WithUseParameterizedCollectionMode(
ParameterizedCollectionMode parameterizedCollectionMode)
ParameterTranslationMode parameterizedCollectionMode)
{
var clone = Clone();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ public RelationalCommandCache(
IRelationalParameterBasedSqlProcessorFactory relationalParameterBasedSqlProcessorFactory,
Expression queryExpression,
bool useRelationalNulls,
ParameterizedCollectionMode parameterizedCollectionMode)
ParameterTranslationMode collectionParameterTranslationMode)
{
_memoryCache = memoryCache;
_querySqlGeneratorFactory = querySqlGeneratorFactory;
_queryExpression = queryExpression;
_relationalParameterBasedSqlProcessor = relationalParameterBasedSqlProcessorFactory.Create(
new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, parameterizedCollectionMode));
new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, collectionParameterTranslationMode));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private SqlParameterExpression VisitSqlParameter(SqlParameterExpression paramete
uniquifiedName,
parameter.Type,
parameter.IsNullable,
parameter.ShouldBeConstantized,
parameter.TranslationMode,
parameter.TypeMapping);

return _sqlParameters[newParameter.InvariantName] = newParameter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ public sealed record RelationalParameterBasedSqlProcessorParameters
/// <summary>
/// Which parametrized collection translation mode should be used.
/// </summary>
public ParameterizedCollectionMode ParameterizedCollectionMode { get; init; }
public ParameterTranslationMode CollectionParameterTranslationMode { get; init; }

/// <summary>
/// Creates a new instance of <see cref="RelationalParameterBasedSqlProcessorParameters" />.
/// </summary>
/// <param name="useRelationalNulls">A value indicating if relational nulls should be used.</param>
/// <param name="parameterizedCollectionMode">Which translation mode should be used.</param>
/// <param name="collectionParameterTranslationMode">Which translation mode should be used.</param>
[EntityFrameworkInternal]
public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, ParameterizedCollectionMode parameterizedCollectionMode)
public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, ParameterTranslationMode collectionParameterTranslationMode)
{
UseRelationalNulls = useRelationalNulls;
ParameterizedCollectionMode = parameterizedCollectionMode;
CollectionParameterTranslationMode = collectionParameterTranslationMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public partial class RelationalQueryableMethodTranslatingExpressionVisitor : Que
private readonly IRelationalTypeMappingSource _typeMappingSource;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly bool _subquery;
private readonly ParameterizedCollectionMode _parameterizedCollectionMode;
private readonly ParameterTranslationMode _collectionParameterTranslationMode;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -64,7 +64,7 @@ public RelationalQueryableMethodTranslatingExpressionVisitor(
_typeMappingSource = relationalDependencies.TypeMappingSource;
_sqlExpressionFactory = sqlExpressionFactory;
_subquery = false;
_parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
_collectionParameterTranslationMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
}

/// <summary>
Expand All @@ -90,7 +90,7 @@ protected RelationalQueryableMethodTranslatingExpressionVisitor(
_typeMappingSource = parentVisitor._typeMappingSource;
_sqlExpressionFactory = parentVisitor._sqlExpressionFactory;
_subquery = true;
_parameterizedCollectionMode = RelationalOptionsExtension.Extract(parentVisitor._queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
_collectionParameterTranslationMode = RelationalOptionsExtension.Extract(parentVisitor._queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
}

/// <inheritdoc />
Expand Down Expand Up @@ -244,7 +244,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
&& methodCallExpression.Arguments[0] is ParameterQueryRootExpression parameterSource
&& TranslateExpression(methodCallExpression.Arguments[1]) is SqlExpression item
&& _sqlTranslator.Visit(parameterSource.QueryParameterExpression) is SqlParameterExpression sqlParameterExpression
&& !parameterSource.QueryParameterExpression.ShouldNotBeConstantized)
&& (parameterSource.QueryParameterExpression.TranslationMode is ParameterTranslationMode.Constant
or null))
{
var inExpression = _sqlExpressionFactory.In(item, sqlParameterExpression);
var selectExpression = new SelectExpression(inExpression, _sqlAliasManager);
Expand Down Expand Up @@ -298,26 +299,24 @@ JsonScalarExpression jsonScalar

var tableAlias = _sqlAliasManager.GenerateTableAlias(sqlParameterExpression.Name.TrimStart('_'));

var constants = queryParameter.ShouldBeConstantized
|| (_parameterizedCollectionMode is ParameterizedCollectionMode.Constants
&& !queryParameter.ShouldNotBeConstantized);
var multipleParameters = _parameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
&& !queryParameter.ShouldNotBeConstantized;
if (constants || multipleParameters)
{
var valuesExpression = new ValuesExpression(
tableAlias,
sqlParameterExpression,
[ValuesOrderingColumnName, ValuesValueColumnName]);
return CreateShapedQueryExpressionForValuesExpression(
valuesExpression,
tableAlias,
parameterQueryRootExpression.ElementType,
sqlParameterExpression.TypeMapping,
sqlParameterExpression.IsNullable);
}

return TranslatePrimitiveCollection(sqlParameterExpression, property: null, tableAlias);
return (queryParameter.TranslationMode ?? _collectionParameterTranslationMode) switch
{
ParameterTranslationMode.Constant or ParameterTranslationMode.MultipleParameters
=> CreateShapedQueryExpressionForValuesExpression(
new ValuesExpression(
tableAlias,
sqlParameterExpression,
[ValuesOrderingColumnName, ValuesValueColumnName]),
tableAlias,
parameterQueryRootExpression.ElementType,
sqlParameterExpression.TypeMapping,
sqlParameterExpression.IsNullable),

ParameterTranslationMode.Parameter
=> TranslatePrimitiveCollection(sqlParameterExpression, property: null, tableAlias),

_ => throw new UnreachableException()
};
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public partial class RelationalShapedQueryCompilingExpressionVisitor : ShapedQue
private readonly bool _threadSafetyChecksEnabled;
private readonly bool _detailedErrorsEnabled;
private readonly bool _useRelationalNulls;
private readonly ParameterizedCollectionMode _parameterizedCollectionMode;
private readonly ParameterTranslationMode _collectionParameterTranslationMode;
private readonly bool _isPrecompiling;

private readonly RelationalParameterBasedSqlProcessor _relationalParameterBasedSqlProcessor;
Expand Down Expand Up @@ -55,15 +55,15 @@ public RelationalShapedQueryCompilingExpressionVisitor(

_relationalParameterBasedSqlProcessor =
relationalDependencies.RelationalParameterBasedSqlProcessorFactory.Create(
new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls, _parameterizedCollectionMode));
new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls, _collectionParameterTranslationMode));
_querySqlGeneratorFactory = relationalDependencies.QuerySqlGeneratorFactory;

_contextType = queryCompilationContext.ContextType;
_tags = queryCompilationContext.Tags;
_threadSafetyChecksEnabled = dependencies.CoreSingletonOptions.AreThreadSafetyChecksEnabled;
_detailedErrorsEnabled = dependencies.CoreSingletonOptions.AreDetailedErrorsEnabled;
_useRelationalNulls = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).UseRelationalNulls;
_parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
_collectionParameterTranslationMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
_isPrecompiling = queryCompilationContext.IsPrecompiling;
}

Expand Down Expand Up @@ -500,7 +500,7 @@ private Expression CreateRelationalCommandResolverExpression(Expression queryExp
RelationalDependencies.RelationalParameterBasedSqlProcessorFactory,
queryExpression,
_useRelationalNulls,
_parameterizedCollectionMode);
_collectionParameterTranslationMode);

var commandLiftableConstant = RelationalDependencies.RelationalLiftableConstantFactory.CreateLiftableConstant(
relationalCommandCache,
Expand Down Expand Up @@ -751,7 +751,7 @@ Expression<Func<RelationalMaterializerLiftableConstantContext, object>> Generate
_relationalDependenciesRelationalParameterBasedSqlProcessorFactoryProperty),
Constant(queryExpression),
Constant(_useRelationalNulls),
Constant(_parameterizedCollectionMode, typeof(ParameterizedCollectionMode))),
Constant(_collectionParameterTranslationMode, typeof(ParameterTranslationMode))),
contextParameter);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
name: queryParameter.Name,
queryParameter.Type,
nullable: false,
queryParameter.ShouldBeConstantized,
queryParameter.TranslationMode,
typeMapping: null);
}

Expand All @@ -525,7 +525,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
name: queryParameter.Name,
queryParameter.Type,
queryParameter.Type.IsNullableType(),
queryParameter.ShouldBeConstantized,
queryParameter.TranslationMode,
typeMapping: null);

case StructuralTypeShaperExpression shaper:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed class SqlParameterExpression : SqlExpression
/// <param name="type">The <see cref="Type" /> of the expression.</param>
/// <param name="typeMapping">The <see cref="RelationalTypeMapping" /> associated with the expression.</param>
public SqlParameterExpression(string name, Type type, RelationalTypeMapping? typeMapping)
: this(invariantName: name, name: name, type.UnwrapNullableType(), type.IsNullableType(), shouldBeConstantized: false, typeMapping)
: this(invariantName: name, name: name, type.UnwrapNullableType(), type.IsNullableType(), translationMode: null, typeMapping)
{
}

Expand All @@ -31,21 +31,21 @@ public SqlParameterExpression(string name, Type type, RelationalTypeMapping? typ
/// </param>
/// <param name="type">The <see cref="Type" /> of the expression.</param>
/// <param name="nullable">Whether this parameter can have null values.</param>
/// <param name="shouldBeConstantized">Whether the user has indicated that this query parameter should be inlined as a constant.</param>
/// <param name="translationMode">How the parameter should be handled.</param>
/// <param name="typeMapping">The <see cref="RelationalTypeMapping" /> associated with the expression.</param>
public SqlParameterExpression(
string invariantName,
string name,
Type type,
bool nullable,
bool shouldBeConstantized,
ParameterTranslationMode? translationMode,
RelationalTypeMapping? typeMapping)
: base(type.UnwrapNullableType(), typeMapping)
{
InvariantName = invariantName;
Name = name;
IsNullable = nullable;
ShouldBeConstantized = shouldBeConstantized;
TranslationMode = translationMode;
}

/// <summary>
Expand All @@ -65,17 +65,17 @@ public SqlParameterExpression(
public bool IsNullable { get; }

/// <summary>
/// Whether the user has indicated that this query parameter should be inlined as a constant.
/// How the parameter should be handled.
/// </summary>
public bool ShouldBeConstantized { get; }
public ParameterTranslationMode? TranslationMode { get; }

/// <summary>
/// Applies supplied type mapping to this expression.
/// </summary>
/// <param name="typeMapping">A relational type mapping to apply.</param>
/// <returns>A new expression which has supplied type mapping.</returns>
public SqlExpression ApplyTypeMapping(RelationalTypeMapping? typeMapping)
=> new SqlParameterExpression(InvariantName, Name, Type, IsNullable, ShouldBeConstantized, typeMapping);
=> new SqlParameterExpression(InvariantName, Name, Type, IsNullable, TranslationMode, typeMapping);

/// <inheritdoc />
protected override Expression VisitChildren(ExpressionVisitor visitor)
Expand Down
Loading