From 5cf05e544b32ed7fe411cb5bbcbaf462d0ec349e Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Tue, 6 May 2025 10:55:50 +0200 Subject: [PATCH] Handle primitive collections as multiple parameters. --- src/EFCore.Relational/EFExtensions.cs | 34 ++ .../RelationalDbContextOptionsBuilder.cs | 42 +- .../RelationalOptionsExtension.cs | 21 +- .../ParameterizedCollectionTranslationMode.cs | 29 -- .../ParameterizedCollectionMode.cs | 56 ++ .../Properties/RelationalStrings.Designer.cs | 6 + .../Properties/RelationalStrings.resx | 3 + .../Query/Internal/RelationalCommandCache.cs | 7 +- .../Internal/RelationalCommandResolver.cs | 2 +- .../RelationalParameterBasedSqlProcessor.cs | 4 +- ...nalParameterBasedSqlProcessorParameters.cs | 13 +- ...yableMethodTranslatingExpressionVisitor.cs | 18 +- ...alShapedQueryCompilingExpressionVisitor.cs | 16 +- .../Query/SqlExpressionFactory.cs | 5 +- .../Query/SqlExpressions/ValuesExpression.cs | 2 +- .../Query/SqlNullabilityProcessor.cs | 176 +++++-- .../Internal/ISqlServerSingletonOptions.cs | 8 + .../Internal/SqlServerSingletonOptions.cs | 13 + .../Internal/SqlServerJsonPostprocessor.cs | 7 +- .../SqlServerParameterBasedSqlProcessor.cs | 14 +- ...ServerParameterBasedSqlProcessorFactory.cs | 14 +- ...yableMethodTranslatingExpressionVisitor.cs | 94 ++-- .../SqlServerSqlNullabilityProcessor.cs | 207 +++++++- .../SqliteParameterBasedSqlProcessor.cs | 2 +- .../Query/Internal/SqliteQuerySqlGenerator.cs | 21 +- ...yableMethodTranslatingExpressionVisitor.cs | 79 ++- src/EFCore/EF.cs | 3 +- .../Internal/ExpressionTreeFuncletizer.cs | 2 +- src/EFCore/Query/Internal/IParameterValues.cs | 2 +- .../NavigationExpandingExpressionVisitor.cs | 6 +- src/EFCore/Query/QueryContext.cs | 6 +- .../PrimitiveCollectionsQueryCosmosTest.cs | 8 + ...HocMiscellaneousQueryRelationalTestBase.cs | 4 +- ...itiveCollectionsQueryRelationalTestBase.cs | 73 ++- .../PrimitiveCollectionsQueryTestBase.cs | 39 ++ .../AdHocMiscellaneousQuerySqlServerTest.cs | 178 +++++-- .../AdHocQueryFiltersQuerySqlServerTest.cs | 16 +- ...avigationsCollectionsQuerySqlServerTest.cs | 21 +- ...CollectionsSharedTypeQuerySqlServerTest.cs | 21 +- ...tionsCollectionsSplitQuerySqlServerTest.cs | 37 +- ...ComplexNavigationsQuerySqlServer160Test.cs | 8 +- .../ComplexNavigationsQuerySqlServerTest.cs | 8 +- ...igationsSharedTypeQuerySqlServer160Test.cs | 8 +- ...NavigationsSharedTypeQuerySqlServerTest.cs | 8 +- .../Query/GearsOfWarQuerySqlServerTest.cs | 170 +++---- ...dPrimitiveCollectionsQuerySqlServerTest.cs | 94 ++-- ...indAggregateOperatorsQuerySqlServerTest.cs | 479 +++++++----------- .../NorthwindCompiledQuerySqlServerTest.cs | 14 +- ...windEFPropertyIncludeQuerySqlServerTest.cs | 58 +-- ...windIncludeNoTrackingQuerySqlServerTest.cs | 58 +-- .../NorthwindIncludeQuerySqlServerTest.cs | 58 +-- .../Query/NorthwindJoinQuerySqlServerTest.cs | 9 +- ...orthwindMiscellaneousQuerySqlServerTest.cs | 103 ++-- .../NorthwindNavigationsQuerySqlServerTest.cs | 12 +- .../NorthwindSelectQuerySqlServerTest.cs | 45 +- ...plitIncludeNoTrackingQuerySqlServerTest.cs | 90 +--- ...NorthwindSplitIncludeQuerySqlServerTest.cs | 90 +--- ...orthwindStringIncludeQuerySqlServerTest.cs | 58 +-- .../Query/NorthwindWhereQuerySqlServerTest.cs | 68 ++- .../Query/NullSemanticsQuerySqlServerTest.cs | 175 ++----- .../Query/PrecompiledQuerySqlServerTest.cs | 9 +- ...piledSqlPregenerationQuerySqlServerTest.cs | 5 +- ...imitiveCollectionsQueryOldSqlServerTest.cs | 299 +++++++++-- ...imitiveCollectionsQuerySqlServer160Test.cs | 400 ++++++--------- ...veCollectionsQuerySqlServerJsonTypeTest.cs | 17 + .../PrimitiveCollectionsQuerySqlServerTest.cs | 399 ++++++--------- .../QueryFilterFuncletizationSqlServerTest.cs | 27 +- .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 170 +++---- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 170 +++---- ...avigationsCollectionsQuerySqlServerTest.cs | 21 +- ...CollectionsSharedTypeQuerySqlServerTest.cs | 21 +- .../TemporalGearsOfWarQuerySqlServerTest.cs | 155 ++---- .../QueryTests.cs | 8 +- .../AdHocMiscellaneousQuerySqliteTest.cs | 4 +- .../Query/GearsOfWarQuerySqliteTest.cs | 159 +++--- ...aredPrimitiveCollectionsQuerySqliteTest.cs | 68 ++- ...thwindAggregateOperatorsQuerySqliteTest.cs | 56 +- .../PrimitiveCollectionsQuerySqliteTest.cs | 404 ++++++--------- 78 files changed, 2621 insertions(+), 2693 deletions(-) create mode 100644 src/EFCore.Relational/EFExtensions.cs delete mode 100644 src/EFCore.Relational/Internal/ParameterizedCollectionTranslationMode.cs create mode 100644 src/EFCore.Relational/ParameterizedCollectionMode.cs diff --git a/src/EFCore.Relational/EFExtensions.cs b/src/EFCore.Relational/EFExtensions.cs new file mode 100644 index 00000000000..c2677cb8706 --- /dev/null +++ b/src/EFCore.Relational/EFExtensions.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore; + +/// +/// Methods that are useful in application code. For example, referencing a shadow state property in a LINQ query. +/// +/// +/// See Database functions and +/// Using EF.Property in EF Core queries for more information and examples. +/// +public static class EFExtensions +{ + /// + /// Methods that are useful in application code. For example, referencing a shadow state property in a LINQ query. + /// + /// + /// See Database functions and + /// Using EF.Property in EF Core queries for more information and examples. + /// + extension(EF) + { + /// + /// Within the context of an EF LINQ query, forces its argument to be inserted into the query as a multiple parameter expressions. + /// + /// Note that this is a static method accessed through the top-level static type. + /// The type of collection element. + /// The collection to be integrated as parameters into the query. + /// The same value for further use in the query. + public static IEnumerable MultipleParameters(IEnumerable argument) + => throw new InvalidOperationException(RelationalStrings.EFMultipleParametersInvoked); + } +} diff --git a/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs b/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs index 1499abf3868..269a68bfb0a 100644 --- a/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs +++ b/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; -using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure; @@ -163,10 +162,9 @@ public virtual TBuilder ExecutionStrategy( /// /// /// - /// When a LINQ query contains a parameterized collection, by default EF Core parameterizes the entire collection as a single - /// SQL parameter, if possible. For example, on SQL Server, the LINQ query Where(b => ids.Contains(b.Id) is translated to - /// WHERE [b].[Id] IN (SELECT [i].[value] FROM OPENJSON(@__ids_0) ...). While this helps with query plan caching, it can - /// produce worse query plans for certain query types. + /// When a LINQ query contains a parameterized collection, by default EF Core translates as a multiple SQL parameters, + /// if possible. For example, on SQL Server, the LINQ query Where(b => ids.Contains(b.Id) is translated to + /// WHERE [b].[Id] IN (@ids1, @ids2, @ids3). /// /// /// instructs EF to translate the collection to a set of constants: @@ -176,36 +174,42 @@ public virtual TBuilder ExecutionStrategy( /// /// Note that it's possible to cause EF to translate a specific collection in a specific query to constants by wrapping the /// parameterized collection in : Where(b => EF.Constant(ids).Contains(b.Id). This overrides - /// the default. Likewise, you can translate a specific collection in a specific query to a single parameter by wrapping the - /// parameterized collection in : Where(b => EF.Parameter(ids).Contains(b.Id). This - /// overrides the setting. + /// the default. /// /// + [Obsolete("Use UseParameterizedCollectionMode instead.")] public virtual TBuilder TranslateParameterizedCollectionsToConstants() - => WithOption(e => (TExtension)e.WithParameterizedCollectionTranslationMode(ParameterizedCollectionTranslationMode.Constantize)); + => UseParameterizedCollectionMode(ParameterizedCollectionMode.Constants); /// - /// Configures the context to translate parameterized collections to parameters. + /// Configures the context to translate parameterized collections to a single array-like parameter. /// /// /// - /// When a LINQ query contains a parameterized collection, by default EF Core parameterizes the entire collection as a single - /// SQL parameter, if possible. For example, on SQL Server, the LINQ query Where(b => ids.Contains(b.Id) is translated to - /// WHERE [b].[Id] IN (SELECT [i].[value] FROM OPENJSON(@__ids_0) ...). While this helps with query plan caching, it can - /// produce worse query plans for certain query types. + /// When a LINQ query contains a parameterized collection, by default EF Core translates as a multiple SQL parameters, + /// if possible. For example, on SQL Server, the LINQ query Where(b => ids.Contains(b.Id) is translated to + /// WHERE [b].[Id] IN (@ids1, @ids2, @ids3). /// /// - /// explicitly instructs EF to perform the default translation - /// of parameterized collections, which is translating them to parameters. + /// instructs EF to translate the collection to a single array-like parameter: + /// WHERE [b].[Id] IN (SELECT [i].[value] FROM OPENJSON(@ids) ...). /// /// - /// Note that it's possible to cause EF to translate a specific collection in a specific query to constants by wrapping the - /// parameterized collection in : Where(b => EF.Constant(ids).Contains(b.Id). This overrides + /// Note that it's possible to cause EF to translate a specific collection in a specific query to parameter by wrapping the + /// parameterized collection in : Where(b => EF.Parameter(ids).Contains(b.Id). This overrides /// the default. /// /// + [Obsolete("Use UseParameterizedCollectionMode instead.")] public virtual TBuilder TranslateParameterizedCollectionsToParameters() - => WithOption(e => (TExtension)e.WithParameterizedCollectionTranslationMode(ParameterizedCollectionTranslationMode.Parameterize)); + => UseParameterizedCollectionMode(ParameterizedCollectionMode.Parameter); + + /// + /// Configures the to use when translating parameterized collections. + /// + /// The same builder instance so that multiple calls can be chained. + public virtual TBuilder UseParameterizedCollectionMode(ParameterizedCollectionMode parameterizedCollectionMode) + => WithOption(e => (TExtension)e.WithUseParameterizedCollectionMode(parameterizedCollectionMode)); /// /// Sets an option by cloning the extension used to store the settings. This ensures the builder diff --git a/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs b/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs index 10ed1eb53ba..e2cc09b80c8 100644 --- a/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs +++ b/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text; -using Microsoft.EntityFrameworkCore.Internal; namespace Microsoft.EntityFrameworkCore.Infrastructure; @@ -37,7 +36,7 @@ public abstract class RelationalOptionsExtension : IDbContextOptionsExtension private string? _migrationsHistoryTableName; private string? _migrationsHistoryTableSchema; private Func? _executionStrategyFactory; - private ParameterizedCollectionTranslationMode? _parameterizedCollectionTranslationMode; + private ParameterizedCollectionMode? _parameterizedCollectionMode; /// /// Creates a new set of options with everything set to default values. @@ -65,7 +64,7 @@ protected RelationalOptionsExtension(RelationalOptionsExtension copyFrom) _migrationsHistoryTableName = copyFrom._migrationsHistoryTableName; _migrationsHistoryTableSchema = copyFrom._migrationsHistoryTableSchema; _executionStrategyFactory = copyFrom._executionStrategyFactory; - _parameterizedCollectionTranslationMode = copyFrom._parameterizedCollectionTranslationMode; + _parameterizedCollectionMode = copyFrom._parameterizedCollectionMode; } /// @@ -387,20 +386,20 @@ public virtual RelationalOptionsExtension WithExecutionStrategyFactory( /// /// Configured translation mode for parameterized collections. /// - public virtual ParameterizedCollectionTranslationMode? ParameterizedCollectionTranslationMode - => _parameterizedCollectionTranslationMode; + public virtual ParameterizedCollectionMode ParameterizedCollectionMode + => _parameterizedCollectionMode ?? ParameterizedCollectionMode.MultipleParameters; /// /// 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 . /// - /// The option to change. - public virtual RelationalOptionsExtension WithParameterizedCollectionTranslationMode( - ParameterizedCollectionTranslationMode parameterizedCollectionTranslationMode) + /// The option to change. + public virtual RelationalOptionsExtension WithUseParameterizedCollectionMode( + ParameterizedCollectionMode parameterizedCollectionMode) { var clone = Clone(); - clone._parameterizedCollectionTranslationMode = parameterizedCollectionTranslationMode; + clone._parameterizedCollectionMode = parameterizedCollectionMode; return clone; } @@ -563,9 +562,9 @@ public override string LogFragment builder.Append(Extension._migrationsHistoryTableName ?? HistoryRepository.DefaultTableName).Append(' '); } - if (Extension._parameterizedCollectionTranslationMode != null) + if (Extension._parameterizedCollectionMode != null) { - builder.Append("ParameterizedCollectionTranslationMode=").Append(Extension._parameterizedCollectionTranslationMode) + builder.Append("ParameterizedCollectionTranslationMode=").Append(Extension._parameterizedCollectionMode) .Append(' '); } diff --git a/src/EFCore.Relational/Internal/ParameterizedCollectionTranslationMode.cs b/src/EFCore.Relational/Internal/ParameterizedCollectionTranslationMode.cs deleted file mode 100644 index cfb59de6f08..00000000000 --- a/src/EFCore.Relational/Internal/ParameterizedCollectionTranslationMode.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.EntityFrameworkCore.Internal; - -/// -/// 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 enum ParameterizedCollectionTranslationMode -{ - /// - /// 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. - /// - Constantize = 0, - - /// - /// 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. - /// - Parameterize, -} diff --git a/src/EFCore.Relational/ParameterizedCollectionMode.cs b/src/EFCore.Relational/ParameterizedCollectionMode.cs new file mode 100644 index 00000000000..89f48bea90a --- /dev/null +++ b/src/EFCore.Relational/ParameterizedCollectionMode.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore; + +/// +/// Indicates how parameterized collections are translated into SQL. +/// +public enum ParameterizedCollectionMode +{ + /// + /// Instructs EF to translate the collection to a set of constants: + /// WHERE [x].[Id] IN (1, 2, 3). + /// + /// + /// + /// This can produce better query plans for certain query types, but can also lead to query + /// plan bloat. + /// + /// + /// Note that it's possible to cause EF to translate a specific collection in a specific query to constants by wrapping the + /// parameterized collection in : Where(x => EF.Constant(ids).Contains(x.Id). This overrides + /// the default. + /// + /// + Constants, + + /// + /// Instructs EF to translate the collection to a single array-like parameter: + /// WHERE [x].[Id] IN (SELECT [i].[value] FROM OPENJSON(@ids) ...). + /// + /// + /// + /// This can produce suboptimal query plans for certain query types. + /// + /// + /// Note that it's possible to cause EF to translate a specific collection in a specific query to parameter by wrapping the + /// parameterized collection in : Where(x => EF.Parameter(ids).Contains(x.Id). This overrides + /// the default. + /// + /// + Parameter, + + /// + /// Instructs EF to translate the collection to a set of parameters: + /// WHERE [x].[Id] IN (@ids1, @ids2, @ids3). + /// + /// + /// + /// Note that it's possible to cause EF to translate a specific collection in a specific query to parameter by wrapping the + /// parameterized collection in : Where(x => EF.MultipleParameters(ids).Contains(x.Id). This overrides + /// the default. + /// + /// + MultipleParameters, +} diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs index 0aa88b18eb3..5707786f56d 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs +++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs @@ -641,6 +641,12 @@ public static string DuplicateSeedDataSensitive(object? entityType, object? keyV GetString("DuplicateSeedDataSensitive", nameof(entityType), nameof(keyValue), nameof(table)), entityType, keyValue, table); + /// + /// The EF.MultipoleParameters<T> method may only be used within Entity Framework LINQ queries. + /// + public static string EFMultipleParametersInvoked + => GetString("EFMultipleParametersInvoked"); + /// /// Empty collections are not supported as inline query roots. /// diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx index 54f1313fe43..a97615cd6ab 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.resx +++ b/src/EFCore.Relational/Properties/RelationalStrings.resx @@ -355,6 +355,9 @@ A seed entity for entity type '{entityType}' has the same key value {keyValue} as another seed entity mapped to the same table '{table}'. Key values should be unique across seed entities. + + The EF.MultipleParameters<T> method may only be used within Entity Framework LINQ queries. + Empty collections are not supported as inline query roots. diff --git a/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs b/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs index a29886eb9d3..15435beed35 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs @@ -34,13 +34,14 @@ public RelationalCommandCache( IQuerySqlGeneratorFactory querySqlGeneratorFactory, IRelationalParameterBasedSqlProcessorFactory relationalParameterBasedSqlProcessorFactory, Expression queryExpression, - bool useRelationalNulls) + bool useRelationalNulls, + ParameterizedCollectionMode parameterizedCollectionMode) { _memoryCache = memoryCache; _querySqlGeneratorFactory = querySqlGeneratorFactory; _queryExpression = queryExpression; _relationalParameterBasedSqlProcessor = relationalParameterBasedSqlProcessorFactory.Create( - new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls)); + new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, parameterizedCollectionMode)); } /// @@ -49,7 +50,7 @@ public RelationalCommandCache( /// 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 virtual IRelationalCommandTemplate GetRelationalCommandTemplate(IReadOnlyDictionary parameters) + public virtual IRelationalCommandTemplate GetRelationalCommandTemplate(Dictionary parameters) { var cacheKey = new CommandCacheKey(_queryExpression, parameters); diff --git a/src/EFCore.Relational/Query/Internal/RelationalCommandResolver.cs b/src/EFCore.Relational/Query/Internal/RelationalCommandResolver.cs index 2e73b0413b9..980d430e44a 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalCommandResolver.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalCommandResolver.cs @@ -9,4 +9,4 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal; /// 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 delegate IRelationalCommandTemplate RelationalCommandResolver(IReadOnlyDictionary parameters); +public delegate IRelationalCommandTemplate RelationalCommandResolver(Dictionary parameters); diff --git a/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessor.cs b/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessor.cs index 876687e18b6..3bf2c39d8cc 100644 --- a/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessor.cs +++ b/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessor.cs @@ -49,7 +49,7 @@ public RelationalParameterBasedSqlProcessor( /// An optimized query expression. public virtual Expression Optimize( Expression queryExpression, - IReadOnlyDictionary parametersValues, + Dictionary parametersValues, out bool canCache) { canCache = true; @@ -72,7 +72,7 @@ public virtual Expression Optimize( /// A processed query expression. protected virtual Expression ProcessSqlNullability( Expression queryExpression, - IReadOnlyDictionary parametersValues, + Dictionary parametersValues, out bool canCache) => new SqlNullabilityProcessor(Dependencies, Parameters).Process(queryExpression, parametersValues, out canCache); diff --git a/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs b/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs index e4e87ee1d01..415a8db6e54 100644 --- a/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs +++ b/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs @@ -13,11 +13,20 @@ public sealed record RelationalParameterBasedSqlProcessorParameters /// public bool UseRelationalNulls { get; init; } + /// + /// Which parametrized collection translation mode should be used. + /// + public ParameterizedCollectionMode ParameterizedCollectionMode { get; init; } + /// /// Creates a new instance of . /// /// A value indicating if relational nulls should be used. + /// Which translation mode should be used. [EntityFrameworkInternal] - public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls) - => UseRelationalNulls = useRelationalNulls; + public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, ParameterizedCollectionMode parameterizedCollectionMode) + { + UseRelationalNulls = useRelationalNulls; + ParameterizedCollectionMode = parameterizedCollectionMode; + } } diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 6ef81381828..848973552c6 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -21,6 +21,7 @@ public partial class RelationalQueryableMethodTranslatingExpressionVisitor : Que private readonly IRelationalTypeMappingSource _typeMappingSource; private readonly ISqlExpressionFactory _sqlExpressionFactory; private readonly bool _subquery; + private readonly ParameterizedCollectionMode _parameterizedCollectionMode; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -63,6 +64,7 @@ public RelationalQueryableMethodTranslatingExpressionVisitor( _typeMappingSource = relationalDependencies.TypeMappingSource; _sqlExpressionFactory = sqlExpressionFactory; _subquery = false; + _parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode; } /// @@ -88,6 +90,7 @@ protected RelationalQueryableMethodTranslatingExpressionVisitor( _typeMappingSource = parentVisitor._typeMappingSource; _sqlExpressionFactory = parentVisitor._sqlExpressionFactory; _subquery = true; + _parameterizedCollectionMode = RelationalOptionsExtension.Extract(parentVisitor._queryCompilationContext.ContextOptions).ParameterizedCollectionMode; } /// @@ -293,13 +296,14 @@ JsonScalarExpression jsonScalar Check.DebugAssert(sqlParameterExpression is not null, "sqlParameterExpression is not null"); - var primitiveCollectionsBehavior = RelationalOptionsExtension.Extract(QueryCompilationContext.ContextOptions) - .ParameterizedCollectionTranslationMode; - var tableAlias = _sqlAliasManager.GenerateTableAlias(sqlParameterExpression.Name.TrimStart('_')); - if (queryParameter.ShouldBeConstantized - || (primitiveCollectionsBehavior == ParameterizedCollectionTranslationMode.Constantize - && !queryParameter.ShouldNotBeConstantized)) + + 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, @@ -569,7 +573,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s return TranslateAny(source, anyLambda); } - // Pattern-match Contains over ValuesExpression, translating to simplified 'item IN (1, 2, 3)' with constant elements + // Pattern-match Contains over ValuesExpression, translating to simplified 'item IN (1, 2, 3)' with constant elements. if (TryExtractBareInlineCollectionValues(source, out var values, out var valuesParameter)) { var inExpression = (values, valuesParameter) switch diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs index fa5f9d7323a..bcd74192e88 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs @@ -19,6 +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 bool _isPrecompiling; private readonly RelationalParameterBasedSqlProcessor _relationalParameterBasedSqlProcessor; @@ -54,7 +55,7 @@ public RelationalShapedQueryCompilingExpressionVisitor( _relationalParameterBasedSqlProcessor = relationalDependencies.RelationalParameterBasedSqlProcessorFactory.Create( - new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls)); + new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls, _parameterizedCollectionMode)); _querySqlGeneratorFactory = relationalDependencies.QuerySqlGeneratorFactory; _contextType = queryCompilationContext.ContextType; @@ -62,6 +63,7 @@ public RelationalShapedQueryCompilingExpressionVisitor( _threadSafetyChecksEnabled = dependencies.CoreSingletonOptions.AreThreadSafetyChecksEnabled; _detailedErrorsEnabled = dependencies.CoreSingletonOptions.AreDetailedErrorsEnabled; _useRelationalNulls = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).UseRelationalNulls; + _parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode; _isPrecompiling = queryCompilationContext.IsPrecompiling; } @@ -497,7 +499,8 @@ private Expression CreateRelationalCommandResolverExpression(Expression queryExp RelationalDependencies.QuerySqlGeneratorFactory, RelationalDependencies.RelationalParameterBasedSqlProcessorFactory, queryExpression, - _useRelationalNulls); + _useRelationalNulls, + _parameterizedCollectionMode); var commandLiftableConstant = RelationalDependencies.RelationalLiftableConstantFactory.CreateLiftableConstant( relationalCommandCache, @@ -505,7 +508,7 @@ private Expression CreateRelationalCommandResolverExpression(Expression queryExp "relationalCommandCache", typeof(RelationalCommandCache)); - var parametersParameter = Parameter(typeof(IReadOnlyDictionary), "parameters"); + var parametersParameter = Parameter(typeof(Dictionary), "parameters"); return Lambda( Call( @@ -542,7 +545,7 @@ bool TryGeneratePregeneratedCommandResolver( return false; } - var parameterDictionaryParameter = Parameter(typeof(IReadOnlyDictionary), "parameters"); + var parameterDictionaryParameter = Parameter(typeof(Dictionary), "parameters"); var resultParameter = Parameter(typeof(IRelationalCommandTemplate), "result"); Expression resolverBody; bool canCache; @@ -657,7 +660,7 @@ static object GenerateNonNullParameterValue(Type type) } } - Expression GenerateRelationalCommandExpression(IReadOnlyDictionary parameters, out bool canCache) + Expression GenerateRelationalCommandExpression(Dictionary parameters, out bool canCache) { var queryExpression = _relationalParameterBasedSqlProcessor.Optimize(select, parameters, out canCache); if (!canCache) @@ -747,7 +750,8 @@ Expression> Generate MakeMemberAccess(contextParameter, _relationalDependenciesProperty), _relationalDependenciesRelationalParameterBasedSqlProcessorFactoryProperty), Constant(queryExpression), - Constant(_useRelationalNulls)), + Constant(_useRelationalNulls), + Constant(_parameterizedCollectionMode, typeof(ParameterizedCollectionMode))), contextParameter); } } diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs index ff0ec799f8a..40a6d13949f 100644 --- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs @@ -293,7 +293,7 @@ private InExpression ApplyTypeMappingOnIn(InExpression inExpression) break; case { ValuesParameter: SqlParameterExpression parameter }: - valuesTypeMapping = parameter.TypeMapping; + valuesTypeMapping = (RelationalTypeMapping?)parameter.TypeMapping?.ElementTypeMapping; break; case { Values: IReadOnlyList values }: @@ -327,7 +327,8 @@ private InExpression ApplyTypeMappingOnIn(InExpression inExpression) break; case { ValuesParameter: SqlParameterExpression parameter }: - inExpression = inExpression.Update(item, (SqlParameterExpression)ApplyTypeMapping(parameter, item.TypeMapping)); + var collectionTypeMapping = Dependencies.TypeMappingSource.FindMapping(parameter.Type, Dependencies.Model, item.TypeMapping); + inExpression = inExpression.Update(item, (SqlParameterExpression)ApplyTypeMapping(parameter, collectionTypeMapping)); break; case { Values: IReadOnlyList values }: diff --git a/src/EFCore.Relational/Query/SqlExpressions/ValuesExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/ValuesExpression.cs index 5c79b84f3bb..b720bbb025a 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/ValuesExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/ValuesExpression.cs @@ -167,7 +167,7 @@ public override Expression Quote() Constant(Alias, typeof(string)), RowValues is not null ? NewArrayInit(typeof(RowValueExpression), RowValues.Select(rv => rv.Quote())) - : Constant(null, typeof(RowValueExpression)), + : Constant(null, typeof(IReadOnlyList)), RelationalExpressionQuotingUtilities.QuoteOrNull(ValuesParameter), NewArrayInit(typeof(string), ColumnNames.Select(Constant)), RelationalExpressionQuotingUtilities.QuoteAnnotations(Annotations)); diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index a26ca0af260..062a79f1bea 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore.Query; @@ -22,6 +23,10 @@ public class SqlNullabilityProcessor : ExpressionVisitor private readonly List _nonNullableColumns; private readonly List _nullValueColumns; private readonly ISqlExpressionFactory _sqlExpressionFactory; + /// + /// Tracks parameters for collection expansion, allowing reuse. + /// + private readonly Dictionary> _collectionParameterExpansionMap; private bool _canCache; /// @@ -35,10 +40,12 @@ public SqlNullabilityProcessor( { Dependencies = dependencies; UseRelationalNulls = parameters.UseRelationalNulls; + ParameterizedCollectionMode = parameters.ParameterizedCollectionMode; _sqlExpressionFactory = dependencies.SqlExpressionFactory; _nonNullableColumns = []; _nullValueColumns = []; + _collectionParameterExpansionMap = []; ParameterValues = null!; } @@ -52,10 +59,15 @@ public SqlNullabilityProcessor( /// protected virtual bool UseRelationalNulls { get; } + /// + /// A value indicating what translation mode to use. + /// + public virtual ParameterizedCollectionMode ParameterizedCollectionMode { get; } + /// /// Dictionary of current parameter values in use. /// - protected virtual IReadOnlyDictionary ParameterValues { get; private set; } + protected virtual Dictionary ParameterValues { get; private set; } /// /// Processes a query expression to apply null semantics and optimize it. @@ -66,12 +78,13 @@ public SqlNullabilityProcessor( /// An optimized query expression. public virtual Expression Process( Expression queryExpression, - IReadOnlyDictionary parameterValues, + Dictionary parameterValues, out bool canCache) { _canCache = true; _nonNullableColumns.Clear(); _nullValueColumns.Clear(); + _collectionParameterExpansionMap.Clear(); ParameterValues = parameterValues; var result = Visit(queryExpression); @@ -116,26 +129,70 @@ protected override Expression VisitExtension(Expression node) case ValuesExpression { ValuesParameter: SqlParameterExpression valuesParameter } valuesExpression: { DoNotCache(); - Check.DebugAssert(valuesParameter.TypeMapping is not null, "valuesParameter.TypeMapping is not null"); - Check.DebugAssert( - valuesParameter.TypeMapping.ElementTypeMapping is not null, - "valuesParameter.TypeMapping.ElementTypeMapping is not null"); - var typeMapping = (RelationalTypeMapping)valuesParameter.TypeMapping.ElementTypeMapping; - var values = (IEnumerable?)ParameterValues[valuesParameter.Name] ?? Array.Empty(); + Check.DebugAssert(valuesParameter.TypeMapping is not null); + Check.DebugAssert(valuesParameter.TypeMapping.ElementTypeMapping is not null); + var elementTypeMapping = (RelationalTypeMapping)valuesParameter.TypeMapping.ElementTypeMapping; + var values = ((IEnumerable?)ParameterValues[valuesParameter.Name])?.Cast().ToList() ?? []; + + var intTypeMapping = (IntTypeMapping?)Dependencies.TypeMappingSource.FindMapping(typeof(int)); + Check.DebugAssert(intTypeMapping is not null); + var valuesOrderingCounter = 1; var processedValues = new List(); - foreach (var value in values) + + switch (ParameterizedCollectionMode) { - processedValues.Add( - new RowValueExpression( - [ - _sqlExpressionFactory.Constant(value, value?.GetType() ?? typeof(object), sensitive: true, typeMapping) - ])); + case ParameterizedCollectionMode.MultipleParameters + when !valuesParameter.ShouldBeConstantized: + { + var expandedParameters = _collectionParameterExpansionMap.GetOrAddNew(valuesParameter); + for (var i = 0; i < values.Count; i++) + { + // Create parameter for value if we didn't create it yet, + // otherwise reuse it. + if (expandedParameters.Count <= i) + { + var parameterName = Uniquifier.Uniquify(valuesParameter.Name, ParameterValues, int.MaxValue); + ParameterValues.Add(parameterName, values[i]); + var parameterExpression = new SqlParameterExpression(parameterName, values[i]?.GetType() ?? typeof(object), elementTypeMapping); + expandedParameters.Add(parameterExpression); + } + + processedValues.Add( + new RowValueExpression( + ProcessValuesOrderingColumn( + valuesExpression, + [expandedParameters[i]], + intTypeMapping, + ref valuesOrderingCounter))); + } + break; + } + + case ParameterizedCollectionMode.Constants: + case ParameterizedCollectionMode.Parameter + when valuesParameter.ShouldBeConstantized: + case ParameterizedCollectionMode.MultipleParameters + when valuesParameter.ShouldBeConstantized: + { + foreach (var value in values) + { + processedValues.Add( + new RowValueExpression( + ProcessValuesOrderingColumn( + valuesExpression, + [_sqlExpressionFactory.Constant(value, value?.GetType() ?? typeof(object), sensitive: true, elementTypeMapping)], + intTypeMapping, + ref valuesOrderingCounter))); + } + break; + } + + default: + throw new UnreachableException(); } - return processedValues is not [] - ? valuesExpression.Update(processedValues) - : valuesExpression; + return valuesExpression.Update(processedValues); } default: @@ -176,6 +233,25 @@ or ExpressionType.LessThan } } + /// + /// If we still have _ord column here (it was not removed by other optimizations), + /// we need to add value for it. + /// + /// Expression where to look for ordering column. + /// Expressions for . + /// Type mapping for integer. + /// Counter for constants for ordering column. + /// Row value with ordering, if needed. + [EntityFrameworkInternal] + protected virtual IReadOnlyList ProcessValuesOrderingColumn( + ValuesExpression valuesExpression, + IReadOnlyList expressions, + IntTypeMapping intTypeMapping, + ref int counter) + => RelationalQueryableMethodTranslatingExpressionVisitor.ValuesOrderingColumnName.Equals(valuesExpression.ColumnNames[0], StringComparison.Ordinal) + ? [_sqlExpressionFactory.Constant(counter++, intTypeMapping), .. expressions] + : expressions; + /// /// Visits a . /// @@ -752,25 +828,66 @@ InExpression ProcessInExpressionValues( // The InExpression has a values parameter. Expand it out, embedding its values as constants into the SQL; disable SQL // caching. DoNotCache(); - var typeMapping = inExpression.ValuesParameter.TypeMapping; - var values = (IEnumerable?)ParameterValues[valuesParameter.Name] ?? Array.Empty(); + var elementTypeMapping = (RelationalTypeMapping)inExpression.ValuesParameter.TypeMapping!.ElementTypeMapping!; + var values = ((IEnumerable?)ParameterValues[valuesParameter.Name])?.Cast().ToList() ?? []; processedValues = []; - foreach (var value in values) + var useParameters = ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters + && !valuesParameter.ShouldBeConstantized; + var useConstants = + ParameterizedCollectionMode is ParameterizedCollectionMode.Constants + || + (ParameterizedCollectionMode is ParameterizedCollectionMode.Parameter + && valuesParameter.ShouldBeConstantized) + || + (ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters + && valuesParameter.ShouldBeConstantized); + var expandedParameters = _collectionParameterExpansionMap.GetOrAddNew(valuesParameter); + var expandedParametersCounter = 0; + for (var i = 0; i < values.Count; i++) { - if (value is null && removeNulls) + if (values[i] is null && removeNulls) { hasNull = true; continue; } - processedValues.Add(_sqlExpressionFactory.Constant(value, value?.GetType() ?? typeof(object), sensitive: true, typeMapping)); + switch (useParameters, useConstants) + { + case (true, false): + { + // Create parameter for value if we didn't create it yet, + // otherwise reuse it. + if (expandedParameters.Count <= i) + { + var parameterName = Uniquifier.Uniquify(valuesParameter.Name, ParameterValues, int.MaxValue); + ParameterValues.Add(parameterName, values[i]); + var parameterExpression = new SqlParameterExpression(parameterName, values[i]?.GetType() ?? typeof(object), elementTypeMapping); + expandedParameters.Add(parameterExpression); + } + + // Use separate counter, because we may skip nulls. + processedValues.Add(expandedParameters[expandedParametersCounter++]); + + break; + } + + case (false, true): + { + processedValues.Add(_sqlExpressionFactory.Constant(values[i], values[i]?.GetType() ?? typeof(object), sensitive: true, elementTypeMapping)); + + break; + } + + default: + throw new UnreachableException(); + }; } } else { - Check.DebugAssert(inExpression.Values is not null, "inExpression.Values is not null"); + Check.DebugAssert(inExpression.Values is not null); for (var i = 0; i < inExpression.Values.Count; i++) { @@ -1745,20 +1862,9 @@ protected virtual bool TryMakeNonNullable( foundNull = true; - // TODO: We currently only have read-only access to the parameter values in the nullability processor (and in all of the - // 2nd-level query pipeline); to need to flow the mutable dictionary in. Note that any modification of parameter values (as - // here) must immediately entail DoNotCache(). - Check.DebugAssert(ParameterValues is Dictionary, "ParameterValues isn't a Dictionary"); - if (ParameterValues is not Dictionary mutableParameterValues) - { - rewrittenSelectExpression = null; - foundNull = null; - return false; - } - var rewrittenParameter = new SqlParameterExpression( collectionParameter.Name + "_without_nulls", collectionParameter.Type, collectionParameter.TypeMapping); - mutableParameterValues[rewrittenParameter.Name] = processedValues; + ParameterValues[rewrittenParameter.Name] = processedValues; var rewrittenCollectionTable = UpdateParameterCollection(collectionTable, rewrittenParameter); // We clone the select expression since Update below doesn't create a pure copy, mutating the original as well (because of diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs index 47728ddbc9d..d5bee2ee720 100644 --- a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs +++ b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs @@ -42,4 +42,12 @@ public interface ISqlServerSingletonOptions : ISingletonOptions /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public int AzureSynapseCompatibilityLevel { get; } + + /// + /// 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 bool SupportsJsonFunctions { get; } } diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs index fdfc97a3697..9e572d824cc 100644 --- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs +++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs @@ -44,6 +44,19 @@ public class SqlServerSingletonOptions : ISqlServerSingletonOptions public virtual int AzureSynapseCompatibilityLevel { get; private set; } = SqlServerOptionsExtension.AzureSynapseDefaultCompatibilityLevel; + /// + /// 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 virtual bool SupportsJsonFunctions => + (EngineType == SqlServerEngineType.SqlServer && SqlServerCompatibilityLevel >= 130) + || + (EngineType == SqlServerEngineType.AzureSql && AzureSqlCompatibilityLevel >= 130) + || + (EngineType == SqlServerEngineType.AzureSynapse); + /// /// 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 diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs index f523032f5cd..32a507b25bf 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs @@ -28,7 +28,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; public sealed class SqlServerJsonPostprocessor( IRelationalTypeMappingSource typeMappingSource, ISqlExpressionFactory sqlExpressionFactory, - SqlAliasManager sqlAliasManager) + SqlAliasManager? sqlAliasManager) : ExpressionVisitor { private readonly List _openjsonOuterAppliesToAdd = new(); @@ -229,6 +229,11 @@ when _columnsToRewrite.TryGetValue((columnExpression.TableAlias, columnExpressio ?? (jsonScalar.Json as ColumnExpression)?.Name ?? "Json"; + // We need to generate an alias here; we always have a manager except + // when called from SqlNullabilityProcessor (where there's no manager), + // but in that scenario we never have to deal with JsonScalarExpression, + // only OpenJsonExpression. + Check.DebugAssert(sqlAliasManager is not null); var tableAlias = sqlAliasManager.GenerateTableAlias(name); var join = new OuterApplyExpression( diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessor.cs index a4a92f9be47..c932ab16655 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessor.cs @@ -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 Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal; + namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// @@ -11,6 +13,8 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerParameterBasedSqlProcessor : RelationalParameterBasedSqlProcessor { + private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions; + /// /// 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 @@ -19,9 +23,11 @@ public class SqlServerParameterBasedSqlProcessor : RelationalParameterBasedSqlPr /// public SqlServerParameterBasedSqlProcessor( RelationalParameterBasedSqlProcessorDependencies dependencies, - RelationalParameterBasedSqlProcessorParameters parameters) + RelationalParameterBasedSqlProcessorParameters parameters, + ISqlServerSingletonOptions sqlServerSingletonOptions) : base(dependencies, parameters) { + _sqlServerSingletonOptions = sqlServerSingletonOptions; } /// @@ -32,7 +38,7 @@ public SqlServerParameterBasedSqlProcessor( /// public override Expression Optimize( Expression queryExpression, - IReadOnlyDictionary parametersValues, + Dictionary parametersValues, out bool canCache) { var optimizedQueryExpression = new SkipTakeCollapsingExpressionVisitor(Dependencies.SqlExpressionFactory) @@ -48,13 +54,13 @@ public override Expression Optimize( /// protected override Expression ProcessSqlNullability( Expression selectExpression, - IReadOnlyDictionary parametersValues, + Dictionary parametersValues, out bool canCache) { Check.NotNull(selectExpression); Check.NotNull(parametersValues); - return new SqlServerSqlNullabilityProcessor(Dependencies, Parameters).Process( + return new SqlServerSqlNullabilityProcessor(Dependencies, Parameters, _sqlServerSingletonOptions).Process( selectExpression, parametersValues, out canCache); } } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessorFactory.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessorFactory.cs index 9d60b17dba7..79995b14649 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessorFactory.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerParameterBasedSqlProcessorFactory.cs @@ -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 Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal; + namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// @@ -11,6 +13,8 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerParameterBasedSqlProcessorFactory : IRelationalParameterBasedSqlProcessorFactory { + private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions; + /// /// 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 @@ -18,8 +22,12 @@ public class SqlServerParameterBasedSqlProcessorFactory : IRelationalParameterBa /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public SqlServerParameterBasedSqlProcessorFactory( - RelationalParameterBasedSqlProcessorDependencies dependencies) - => Dependencies = dependencies; + RelationalParameterBasedSqlProcessorDependencies dependencies, + ISqlServerSingletonOptions sqlServerSingletonOptions) + { + Dependencies = dependencies; + _sqlServerSingletonOptions = sqlServerSingletonOptions; + } /// /// Relational provider-specific dependencies for this service. @@ -33,5 +41,5 @@ public SqlServerParameterBasedSqlProcessorFactory( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual RelationalParameterBasedSqlProcessor Create(RelationalParameterBasedSqlProcessorParameters parameters) - => new SqlServerParameterBasedSqlProcessor(Dependencies, parameters); + => new SqlServerParameterBasedSqlProcessor(Dependencies, parameters, _sqlServerSingletonOptions); } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs index ca8d8690824..e6de72208ea 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs @@ -334,36 +334,69 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr Expression index, bool returnDefault) { - // TODO: Make sure we want to actually transform to JSON_VALUE, #30981 - if (!returnDefault - && source.QueryExpression is SelectExpression + if (!returnDefault) + { + switch (source.QueryExpression) { - Tables: [SqlServerOpenJsonExpression { Arguments: [var jsonArrayColumn] } openJsonExpression], - Predicate: null, - GroupBy: [], - Having: null, - IsDistinct: false, - Limit: null, - Offset: null, - // We can only apply the indexing if the JSON array is ordered by its natural ordered, i.e. by the "key" column that - // we created in TranslateCollection. For example, if another ordering has been applied (e.g. by the JSON elements - // themselves), we can no longer simply index into the original array. - Orderings: - [ - { - Expression: SqlUnaryExpression + // index on parameter using a column + // translate via JSON because it is a better translation + case SelectExpression + { + Tables: [ValuesExpression { ValuesParameter: { } valuesParameter }], + Predicate: null, + GroupBy: [], + Having: null, + IsDistinct: false, +#pragma warning disable EF1001 + Orderings: [{ Expression: ColumnExpression { Name: ValuesOrderingColumnName }, IsAscending: true }], +#pragma warning restore EF1001 + Limit: null, + Offset: null + } selectExpression + when TranslateExpression(index) is { } translatedIndex + && _sqlServerSingletonOptions.SupportsJsonFunctions + && TryTranslate(selectExpression, valuesParameter, translatedIndex, out var result): + return result; + + // Index on JSON array + case SelectExpression + { + Tables: [SqlServerOpenJsonExpression { Arguments: [var jsonArrayColumn] } openJsonExpression], + Predicate: null, + GroupBy: [], + Having: null, + IsDistinct: false, + Limit: null, + Offset: null, + // We can only apply the indexing if the JSON array is ordered by its natural ordered, i.e. by the "key" column that + // we created in TranslateCollection. For example, if another ordering has been applied (e.g. by the JSON elements + // themselves), we can no longer simply index into the original array. + Orderings: + [ { - OperatorType: ExpressionType.Convert, - Operand: ColumnExpression { Name: "key", TableAlias: var orderingTableAlias } + Expression: SqlUnaryExpression + { + OperatorType: ExpressionType.Convert, + Operand: ColumnExpression { Name: "key", TableAlias: var orderingTableAlias } + } } - } - ] - } selectExpression - && TranslateExpression(index) is { } translatedIndex - && orderingTableAlias == openJsonExpression.Alias) - { - // Index on JSON array + ] + } selectExpression + when orderingTableAlias == openJsonExpression.Alias + && TranslateExpression(index) is { } translatedIndex + && TryTranslate(selectExpression, jsonArrayColumn, translatedIndex, out var result): + return result; + } + } + return base.TranslateElementAtOrDefault(source, index, returnDefault); + + bool TryTranslate( + SelectExpression selectExpression, + SqlExpression jsonArrayColumn, + SqlExpression translatedIndex, + [NotNullWhen(true)] out ShapedQueryExpression? result) + { // Extract the column projected out of the source, and simplify the subquery to a simple JsonScalarExpression var shaperExpression = source.ShaperExpression; if (shaperExpression is UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression @@ -402,14 +435,15 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr projectionColumn.IsNullable); #pragma warning disable EF1001 - return source.UpdateQueryExpression( - new SelectExpression(translation, _queryCompilationContext.SqlAliasManager)); + result = source.UpdateQueryExpression(new SelectExpression(translation, _queryCompilationContext.SqlAliasManager)); #pragma warning restore EF1001 + return true; } } - } - return base.TranslateElementAtOrDefault(source, index, returnDefault); + result = default; + return false; + } } /// diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs index a3fb56ea225..0fb3d4f51e6 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs @@ -1,8 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal; namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; @@ -14,6 +19,19 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerSqlNullabilityProcessor : SqlNullabilityProcessor { + /// + /// 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. + /// + [EntityFrameworkInternal] + public const string OpenJsonParameterTableName = "__openjson"; + + private readonly ISqlServerSingletonOptions _sqlServerSingletonOptions; + + private int _openJsonAliasCounter; + /// /// 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 @@ -22,9 +40,24 @@ public class SqlServerSqlNullabilityProcessor : SqlNullabilityProcessor /// public SqlServerSqlNullabilityProcessor( RelationalParameterBasedSqlProcessorDependencies dependencies, - RelationalParameterBasedSqlProcessorParameters parameters) + RelationalParameterBasedSqlProcessorParameters parameters, + ISqlServerSingletonOptions sqlServerSingletonOptions) : base(dependencies, parameters) { + _sqlServerSingletonOptions = sqlServerSingletonOptions; + } + + /// + /// 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 override Expression Process(Expression queryExpression, Dictionary parameterValues, out bool canCache) + { + var result = base.Process(queryExpression, parameterValues, out canCache); + _openJsonAliasCounter = 0; + return result; } /// @@ -145,5 +178,177 @@ protected override TableExpressionBase UpdateParameterCollection( => table is SqlServerOpenJsonExpression { Arguments: [SqlParameterExpression] } openJsonExpression ? openJsonExpression.Update(newCollectionParameter, path: null) : base.UpdateParameterCollection(table, newCollectionParameter); + + /// + /// 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. + /// + protected override Expression VisitExtension(Expression node) + { + switch (node) + { + case ValuesExpression { ValuesParameter: SqlParameterExpression valuesParameter } valuesExpression + when ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters: + { + Check.DebugAssert(valuesParameter.TypeMapping is not null); + Check.DebugAssert(valuesParameter.TypeMapping.ElementTypeMapping is not null); + var elementTypeMapping = (RelationalTypeMapping)valuesParameter.TypeMapping.ElementTypeMapping; + + if (TryHandleOverLimitParameters( + valuesParameter, + elementTypeMapping, + valuesExpression, + out var openJson, + out var constants, + out _)) + { + switch (openJson, constants) + { + case (not null, null): + return openJson; + + case (null, not null): + Check.DebugAssert(constants.All(x => x is RowValueExpression)); + return valuesExpression.Update([.. constants.Cast()]); + + default: + throw new UnreachableException(); + } + } + return base.VisitExtension(node); + } + + default: + return base.VisitExtension(node); + } + } + + /// + /// 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. + /// + protected override SqlExpression VisitIn(InExpression inExpression, bool allowOptimizedExpansion, out bool nullable) + { + switch (inExpression.ValuesParameter) + { + case SqlParameterExpression valuesParameter + when ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters: + { + Check.DebugAssert(valuesParameter.TypeMapping is not null); + Check.DebugAssert(valuesParameter.TypeMapping.ElementTypeMapping is not null); + var elementTypeMapping = (RelationalTypeMapping)valuesParameter.TypeMapping.ElementTypeMapping; + + if (TryHandleOverLimitParameters( + valuesParameter, + elementTypeMapping, + valuesExpression: null, + out var openJson, + out var constants, + out var containsNulls)) + { + inExpression = (openJson, constants) switch + { + (not null, null) + => inExpression.Update( + inExpression.Item, + SelectExpression.CreateImmutable( + null!, + [openJson], + [ + new ProjectionExpression( + new ColumnExpression( + "value", + openJson.Alias, + valuesParameter.Type.GetSequenceType(), + elementTypeMapping, + containsNulls!.Value), + "value") + ], + null!)), + + (null, not null) => inExpression.Update(inExpression.Item, constants), + + _ => throw new UnreachableException(), + }; + } + return base.VisitIn(inExpression, allowOptimizedExpansion, out nullable); + } + + default: + return base.VisitIn(inExpression, allowOptimizedExpansion, out nullable); + } + } + + private bool TryHandleOverLimitParameters( + SqlParameterExpression valuesParameter, + RelationalTypeMapping typeMapping, + ValuesExpression? valuesExpression, + out SqlServerOpenJsonExpression? openJsonResult, + out List? constantsResult, + out bool? containsNulls) + { + DoNotCache(); + var values = ((IEnumerable?)ParameterValues[valuesParameter.Name])?.Cast().ToList() ?? []; + // SQL Server has limit on number of parameters in a query. + // If we're over that limit, we switch to using single parameter + // and processing it through JSON functions. + if (values.Count > 2098) + { + if (_sqlServerSingletonOptions.SupportsJsonFunctions) + { + var openJsonExpression = new SqlServerOpenJsonExpression( + valuesExpression?.Alias ?? $"{OpenJsonParameterTableName}{_openJsonAliasCounter++}", + valuesParameter, + columnInfos: + [ + new SqlServerOpenJsonExpression.ColumnInfo + { + Name = "value", + TypeMapping = typeMapping, + Path = [], + } + ]); + var jsonPostprocessor = new SqlServerJsonPostprocessor( + Dependencies.TypeMappingSource, + Dependencies.SqlExpressionFactory, + sqlAliasManager: null); + openJsonResult = (SqlServerOpenJsonExpression)jsonPostprocessor.Process(openJsonExpression); + constantsResult = default; + containsNulls = values.Any(static x => x is null); + return true; + } + else + { + var intTypeMapping = (IntTypeMapping)Dependencies.TypeMappingSource.FindMapping(typeof(int))!; + var counter = 1; + + constantsResult = new List(); + foreach (var value in values) + { + constantsResult.Add( + valuesExpression is not null + ? new RowValueExpression( + ProcessValuesOrderingColumn( + valuesExpression, + [Dependencies.SqlExpressionFactory.Constant(value, value?.GetType() ?? typeof(object), sensitive: true, typeMapping)], + intTypeMapping, + ref counter)) + : Dependencies.SqlExpressionFactory.Constant(value, value?.GetType() ?? typeof(object), sensitive: true, typeMapping)); + } + + openJsonResult = default; + containsNulls = default; + return true; + } + } + openJsonResult = default; + constantsResult = default; + containsNulls = default; + return false; + } #pragma warning restore EF1001 } diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteParameterBasedSqlProcessor.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteParameterBasedSqlProcessor.cs index 122c90235ee..3e62bf8e9a4 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteParameterBasedSqlProcessor.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteParameterBasedSqlProcessor.cs @@ -32,7 +32,7 @@ public SqliteParameterBasedSqlProcessor( /// protected override Expression ProcessSqlNullability( Expression queryExpression, - IReadOnlyDictionary parametersValues, + Dictionary parametersValues, out bool canCache) => new SqliteSqlNullabilityProcessor(Dependencies, Parameters).Process(queryExpression, parametersValues, out canCache); } diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs index e14d97b1eff..952c270cecd 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQuerySqlGenerator.cs @@ -103,14 +103,19 @@ protected override void GenerateSetOperationOperand(SetOperationBase setOperatio // however, we can instead wrap the nested set operation in a SELECT * FROM () to achieve the same effect. // The following is a copy-paste of the base implementation from QuerySqlGenerator, adding the SELECT. - // INTERSECT has higher precedence over UNION and EXCEPT, but otherwise evaluation is left-to-right. - // To preserve evaluation order, add parentheses whenever a set operation is nested within a different set operation - // - including different distinctness. - // In addition, EXCEPT is non-commutative (unlike UNION/INTERSECT), so add parentheses for that case too (see #36105). - if (TryUnwrapBareSetOperation(operand, out var nestedSetOperation) - && (nestedSetOperation is ExceptExpression - || nestedSetOperation.GetType() != setOperation.GetType() - || nestedSetOperation.IsDistinct != setOperation.IsDistinct)) + if ( + // INTERSECT has higher precedence over UNION and EXCEPT, but otherwise evaluation is left-to-right. + // To preserve evaluation order, add parentheses whenever a set operation is nested within a different set operation + // - including different distinctness. + // In addition, EXCEPT is non-commutative (unlike UNION/INTERSECT), so add parentheses for that case too (see #36105). + (TryUnwrapBareSetOperation(operand, out var nestedSetOperation) + && (nestedSetOperation is ExceptExpression + || nestedSetOperation.GetType() != setOperation.GetType() + || nestedSetOperation.IsDistinct != setOperation.IsDistinct)) + || + // ValuesExpression with multiple rows uses UNION ALL by default. + // We wrap it in a SELECT * FROM () to ensure that the rows are treated as a single set operation. + (operand is { Tables: [ValuesExpression { RowValues.Count: > 1 }] })) { Sql.AppendLine("SELECT * FROM ("); diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs index b841caf5bc6..4d73e72d2b6 100644 --- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Sqlite.Internal; @@ -469,29 +470,59 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr Expression index, bool returnDefault) { - if (!returnDefault - && source.QueryExpression is SelectExpression + if (!returnDefault) + { + switch (source.QueryExpression) { - Tables: - [ - TableValuedFunctionExpression + // index on parameter using a column + // translate via JSON because it is a better translation + case SelectExpression { - Name: "json_each", Schema: null, IsBuiltIn: true, Arguments: [var jsonArrayColumn] - } jsonEachExpression - ], - Predicate: null, - GroupBy: [], - Having: null, - IsDistinct: false, - Orderings: [{ Expression: ColumnExpression { Name: JsonEachKeyColumnName } orderingColumn, IsAscending: true }], - Limit: null, - Offset: null - } selectExpression - && orderingColumn.TableAlias == jsonEachExpression.Alias - && TranslateExpression(index) is { } translatedIndex) - { - // Index on JSON array + Tables: [ValuesExpression { ValuesParameter: { } valuesParameter }], + Predicate: null, + GroupBy: [], + Having: null, + IsDistinct: false, +#pragma warning disable EF1001 + Orderings: [{ Expression: ColumnExpression { Name: ValuesOrderingColumnName }, IsAscending: true }], +#pragma warning restore EF1001 + Limit: null, + Offset: null + } selectExpression + when TranslateExpression(index) is { } translatedIndex + && TryTranslate(selectExpression, valuesParameter, translatedIndex, out var result): + return result; + + // Index on JSON array + case SelectExpression + { + Tables: [TableValuedFunctionExpression + { + Name: "json_each", Schema: null, IsBuiltIn: true, Arguments: [var jsonArrayColumn] + } jsonEachExpression], + Predicate: null, + GroupBy: [], + Having: null, + IsDistinct: false, + Orderings: [{ Expression: ColumnExpression { Name: JsonEachKeyColumnName } orderingColumn, IsAscending: true }], + Limit: null, + Offset: null + } selectExpression + when orderingColumn.TableAlias == jsonEachExpression.Alias + && TranslateExpression(index) is { } translatedIndex + && TryTranslate(selectExpression, jsonArrayColumn, translatedIndex, out var result): + return result; + } + } + + return base.TranslateElementAtOrDefault(source, index, returnDefault); + bool TryTranslate( + SelectExpression selectExpression, + SqlExpression jsonArrayColumn, + SqlExpression translatedIndex, + [NotNullWhen(true)]out ShapedQueryExpression? result) + { // Extract the column projected out of the source, and simplify the subquery to a simple JsonScalarExpression var shaperExpression = source.ShaperExpression; if (shaperExpression is UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression @@ -520,12 +551,14 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr } #pragma warning disable EF1001 - return source.UpdateQueryExpression(new SelectExpression(translation, _sqlAliasManager)); + result = source.UpdateQueryExpression(new SelectExpression(translation, _sqlAliasManager)); #pragma warning restore EF1001 + return true; } - } - return base.TranslateElementAtOrDefault(source, index, returnDefault); + result = default; + return false; + } } /// diff --git a/src/EFCore/EF.cs b/src/EFCore/EF.cs index f7a5c0b5713..6a5645e1afa 100644 --- a/src/EFCore/EF.cs +++ b/src/EFCore/EF.cs @@ -6,8 +6,7 @@ namespace Microsoft.EntityFrameworkCore; /// -/// Static methods that are useful in application code where there is not an EF type for the method to be accessed from. For example, -/// referencing a shadow state property in a LINQ query. +/// Methods that are useful in application code. For example, referencing a shadow state property in a LINQ query. /// /// /// See Database functions and diff --git a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs index e3788085ea8..3319a97ef4f 100644 --- a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs +++ b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs @@ -2335,7 +2335,7 @@ private sealed class DummyParameterValues : IParameterValues { private readonly Dictionary _parameterValues = new(); - public IReadOnlyDictionary ParameterValues + public Dictionary ParameterValues => _parameterValues; public void AddParameter(string name, object? value) diff --git a/src/EFCore/Query/Internal/IParameterValues.cs b/src/EFCore/Query/Internal/IParameterValues.cs index 8d52ce91f32..ec5a3eeb338 100644 --- a/src/EFCore/Query/Internal/IParameterValues.cs +++ b/src/EFCore/Query/Internal/IParameterValues.cs @@ -17,7 +17,7 @@ public interface IParameterValues /// 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. /// - IReadOnlyDictionary ParameterValues { get; } + Dictionary ParameterValues { get; } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs index a2acda8b3e2..48211e9b303 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs @@ -2304,10 +2304,10 @@ private static Expression SnapshotExpression(Expression selector) private sealed class Parameters : IParameterValues { - private readonly IDictionary _parameterValues = new Dictionary(); + private readonly Dictionary _parameterValues = new Dictionary(); - public IReadOnlyDictionary ParameterValues - => (IReadOnlyDictionary)_parameterValues; + public Dictionary ParameterValues + => _parameterValues; public void AddParameter(string name, object? value) => _parameterValues.Add(name, value); diff --git a/src/EFCore/Query/QueryContext.cs b/src/EFCore/Query/QueryContext.cs index 9237d7ff653..87724f24890 100644 --- a/src/EFCore/Query/QueryContext.cs +++ b/src/EFCore/Query/QueryContext.cs @@ -21,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query; /// public abstract class QueryContext : IParameterValues { - private readonly IDictionary _parameterValues = new Dictionary(); + private readonly Dictionary _parameterValues = new Dictionary(); private IStateManager? _stateManager; /// @@ -97,8 +97,8 @@ public virtual IDiagnosticsLogger QueryLogger /// /// The parameter values to use while executing the query. /// - public virtual IReadOnlyDictionary ParameterValues - => (IReadOnlyDictionary)_parameterValues; + public virtual Dictionary ParameterValues + => _parameterValues; /// /// Adds a parameter to for this query. diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs index 7324f4480e4..6b09305e63d 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs @@ -899,6 +899,14 @@ public override async Task Parameter_collection_Count_with_column_predicate_with Assert.Equal(CoreStrings.EFConstantNotSupported, exception.Message); } + // nothing to test here + public override Task Parameter_collection_Count_with_huge_number_of_values(bool async) + => base.Parameter_collection_Count_with_huge_number_of_values(async); + + // nothing to test here + public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + public override Task Column_collection_of_ints_Contains(bool async) => CosmosTestHelpers.Instance.NoSyncTest( async, async a => diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs index 65ed5fd090c..365953882cd 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs @@ -268,7 +268,7 @@ public class Entity #region Inlined redacting - protected abstract DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder); + protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode); [ConditionalTheory] [MemberData(nameof(InlinedRedactingData))] @@ -277,7 +277,7 @@ public virtual async Task Check_inlined_constants_redacting(bool async, bool ena var contextFactory = await InitializeAsync( onConfiguring: o => { - SetTranslateParameterizedCollectionsToConstants(o); + SetParameterizedCollectionMode(o, ParameterizedCollectionMode.Constants); o.EnableSensitiveDataLogging(enableSensitiveDataLogging); }); using var context = contextFactory.CreateContext(); diff --git a/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs index 91595f5bfc7..2cc15f6fafd 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs @@ -12,9 +12,7 @@ public abstract class NonSharedPrimitiveCollectionsQueryRelationalTestBase(NonSh public override Task Array_of_byte() => AssertTranslationFailed(() => TestArray((byte)1, (byte)2)); - protected abstract DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder); - - protected abstract DbContextOptionsBuilder SetTranslateParameterizedCollectionsToParameters(DbContextOptionsBuilder optionsBuilder); + protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode); [ConditionalFact] public virtual async Task Column_collection_inside_json_owned_entity() @@ -42,7 +40,7 @@ public virtual async Task Column_collection_inside_json_owned_entity() public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_constants() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToConstants(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Constants), seed: context => { context.AddRange( @@ -59,10 +57,10 @@ public virtual async Task Parameter_collection_Count_with_column_predicate_with_ } [ConditionalFact] - public virtual async Task Parameter_collection_of_ints_Contains_int_with_default_constants() + public virtual async Task Parameter_collection_Contains_with_default_constants() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToConstants(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Constants), seed: context => { context.AddRange( @@ -83,7 +81,7 @@ public virtual async Task Parameter_collection_of_ints_Contains_int_with_default public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_constants_EF_Parameter() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToConstants(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Constants), seed: context => { context.AddRange( @@ -101,10 +99,10 @@ public virtual async Task Parameter_collection_Count_with_column_predicate_with_ } [ConditionalFact] - public virtual async Task Parameter_collection_of_ints_Contains_int_with_default_constants_EF_Parameter() + public virtual async Task Parameter_collection_Contains_with_default_constants_EF_Parameter() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToConstants(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Constants), seed: context => { context.AddRange( @@ -122,10 +120,10 @@ public virtual async Task Parameter_collection_of_ints_Contains_int_with_default } [ConditionalFact] - public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_parameters() + public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_parameter() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToParameters(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Parameter), seed: context => { context.AddRange( @@ -142,10 +140,10 @@ public virtual async Task Parameter_collection_Count_with_column_predicate_with_ } [ConditionalFact] - public virtual async Task Parameter_collection_of_ints_Contains_int_with_default_parameters() + public virtual async Task Parameter_collection_Contains_with_default_parameter() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToParameters(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Parameter), seed: context => { context.AddRange( @@ -163,10 +161,10 @@ public virtual async Task Parameter_collection_of_ints_Contains_int_with_default } [ConditionalFact] - public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_parameters_EF_Constant() + public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_parameter_EF_Constant() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToParameters(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Parameter), seed: context => { context.AddRange( @@ -183,10 +181,10 @@ public virtual async Task Parameter_collection_Count_with_column_predicate_with_ } [ConditionalFact] - public virtual async Task Parameter_collection_of_ints_Contains_int_with_default_parameters_EF_Constant() + public virtual async Task Parameter_collection_Contains_with_default_parameter_EF_Constant() { var contextFactory = await InitializeAsync( - onConfiguring: b => SetTranslateParameterizedCollectionsToParameters(b), + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.Parameter), seed: context => { context.AddRange( @@ -203,6 +201,47 @@ public virtual async Task Parameter_collection_of_ints_Contains_int_with_default Assert.Equivalent(new[] { 2 }, result); } + [ConditionalFact] + public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_multiple_parameters() + { + var contextFactory = await InitializeAsync( + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.MultipleParameters), + seed: context => + { + context.AddRange( + new TestEntity { Id = 1 }, + new TestEntity { Id = 100 }); + return context.SaveChangesAsync(); + }); + + await using var context = contextFactory.CreateContext(); + + var ids = new[] { 2, 999 }; + var result = await context.Set().Where(c => ids.Count(i => i > c.Id) == 1).Select(x => x.Id).ToListAsync(); + Assert.Equivalent(new[] { 100 }, result); + } + + [ConditionalFact] + public virtual async Task Parameter_collection_Contains_with_default_multiple_parameters() + { + var contextFactory = await InitializeAsync( + onConfiguring: b => SetParameterizedCollectionMode(b, ParameterizedCollectionMode.MultipleParameters), + seed: context => + { + context.AddRange( + new TestEntity { Id = 1 }, + new TestEntity { Id = 2 }, + new TestEntity { Id = 100 }); + return context.SaveChangesAsync(); + }); + + await using var context = contextFactory.CreateContext(); + + var ints = new[] { 2, 999 }; + var result = await context.Set().Where(c => ints.Contains(c.Id)).Select(x => x.Id).ToListAsync(); + Assert.Equivalent(new[] { 2 }, result); + } + protected class TestOwner { public int Id { get; set; } diff --git a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs index 56c5f161467..6c4b2596051 100644 --- a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs @@ -8,6 +8,8 @@ namespace Microsoft.EntityFrameworkCore.Query; public abstract class PrimitiveCollectionsQueryTestBase(TFixture fixture) : QueryTestBase(fixture) where TFixture : PrimitiveCollectionsQueryTestBase.PrimitiveCollectionsQueryFixtureBase, new() { + public virtual int? NumberOfValuesForHugeParameterCollectionTests { get; } = null; + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Inline_collection_of_ints_Contains(bool async) @@ -674,6 +676,43 @@ public virtual Task Parameter_collection_Count_with_column_predicate_with_EF_Con ss => ss.Set().Where(c => ids.Count(i => i > c.Id) == 2)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Parameter_collection_Count_with_huge_number_of_values(bool async) + { + if (NumberOfValuesForHugeParameterCollectionTests is null) + { + return Task.CompletedTask; + } + + var extra = Enumerable.Range(1000, (int)NumberOfValuesForHugeParameterCollectionTests); + var ids = new[] { 2, 999 }.Concat(extra).ToArray(); + + return AssertQuery( + async, + ss => ss.Set().Where(c => ids.Count(i => i > c.Id) > 0)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + { + if (NumberOfValuesForHugeParameterCollectionTests is null) + { + return; + } + + var extra = Enumerable.Range(1000, (int)NumberOfValuesForHugeParameterCollectionTests); + var ints = new[] { 10, 999 }.Concat(extra).ToArray(); + + await AssertQuery( + async, + ss => ss.Set().Where(c => ints.Contains(c.Int))); + await AssertQuery( + async, + ss => ss.Set().Where(c => !ints.Contains(c.Int))); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Column_collection_of_ints_Contains(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs index 8d59ea02a37..cc0a312389c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs @@ -19,9 +19,9 @@ public class AdHocMiscellaneousQuerySqlServerTest(NonSharedFixture fixture) : Ad protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance; - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) { - new SqlServerDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); + new SqlServerDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); return optionsBuilder; } @@ -548,14 +548,11 @@ public virtual async Task DateTime_Contains_with_smalldatetime_generates_correct AssertSql( """ -@testDateList='["2018-10-07T00:00:00"]' (Size = 4000) +@testDateList1='2018-10-07T00:00:00.0000000' (DbType = DateTime) SELECT [r].[Id], [r].[MyTime] FROM [ReproEntity] AS [r] -WHERE [r].[MyTime] IN ( - SELECT [t].[value] - FROM OPENJSON(@testDateList) WITH ([value] smalldatetime '$') AS [t] -) +WHERE [r].[MyTime] = @testDateList1 """); } @@ -722,54 +719,131 @@ public async Task Where_contains_DateTime_literals(bool async) AssertSql( """ -@dateTimes='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes0='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes1='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes2='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes3='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes4='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes5='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes6='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes7='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes8='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) -@dateTimes9='["1970-09-03T12:00:00","1971-09-03T12:00:10.22","1972-09-03T12:00:10.333","1973-09-03T12:00:10","1974-09-03T12:00:10.5","1975-09-03T12:00:10.66","1976-09-03T12:00:10.777","1977-09-03T12:00:10.888","1978-09-03T12:00:10.999","1979-09-03T12:00:10.111","1980-09-03T12:00:10.222"]' (Size = 4000) +@dateTimes1='1970-09-03T12:00:00.0000000' (DbType = DateTime) +@dateTimes2='1971-09-03T12:00:10.2200000' (DbType = DateTime) +@dateTimes3='1972-09-03T12:00:10.3330000' (DbType = DateTime) +@dateTimes4='1973-09-03T12:00:10.0000000' (DbType = DateTime) +@dateTimes5='1974-09-03T12:00:10.5000000' (DbType = DateTime) +@dateTimes6='1975-09-03T12:00:10.6600000' (DbType = DateTime) +@dateTimes7='1976-09-03T12:00:10.7770000' (DbType = DateTime) +@dateTimes8='1977-09-03T12:00:10.8880000' (DbType = DateTime) +@dateTimes9='1978-09-03T12:00:10.9990000' (DbType = DateTime) +@dateTimes10='1979-09-03T12:00:10.1110000' (DbType = DateTime) +@dateTimes11='1980-09-03T12:00:10.2220000' (DbType = DateTime) +@dateTimes12='1970-09-03T12:00:00.0000000' (DbType = DateTime) +@dateTimes13='1971-09-03T12:00:10.2200000' (DbType = DateTime) +@dateTimes14='1972-09-03T12:00:10.3330000' (DbType = DateTime) +@dateTimes15='1973-09-03T12:00:10.0000000' (DbType = DateTime) +@dateTimes16='1974-09-03T12:00:10.5000000' (DbType = DateTime) +@dateTimes17='1975-09-03T12:00:10.6600000' (DbType = DateTime) +@dateTimes18='1976-09-03T12:00:10.7770000' (DbType = DateTime) +@dateTimes19='1977-09-03T12:00:10.8880000' (DbType = DateTime) +@dateTimes20='1978-09-03T12:00:10.9990000' (DbType = DateTime) +@dateTimes21='1979-09-03T12:00:10.1110000' (DbType = DateTime) +@dateTimes22='1980-09-03T12:00:10.2220000' (DbType = DateTime) +@dateTimes23='1970-09-03T12:00:00.0000000' +@dateTimes24='1971-09-03T12:00:10.2200000' +@dateTimes25='1972-09-03T12:00:10.3330000' +@dateTimes26='1973-09-03T12:00:10.0000000' +@dateTimes27='1974-09-03T12:00:10.5000000' +@dateTimes28='1975-09-03T12:00:10.6600000' +@dateTimes29='1976-09-03T12:00:10.7770000' +@dateTimes30='1977-09-03T12:00:10.8880000' +@dateTimes31='1978-09-03T12:00:10.9990000' +@dateTimes32='1979-09-03T12:00:10.1110000' +@dateTimes33='1980-09-03T12:00:10.2220000' +@dateTimes34='1970-09-03T12:00:00.0000000' +@dateTimes35='1971-09-03T12:00:10.2200000' +@dateTimes36='1972-09-03T12:00:10.3330000' +@dateTimes37='1973-09-03T12:00:10.0000000' +@dateTimes38='1974-09-03T12:00:10.5000000' +@dateTimes39='1975-09-03T12:00:10.6600000' +@dateTimes40='1976-09-03T12:00:10.7770000' +@dateTimes41='1977-09-03T12:00:10.8880000' +@dateTimes42='1978-09-03T12:00:10.9990000' +@dateTimes43='1979-09-03T12:00:10.1110000' +@dateTimes44='1980-09-03T12:00:10.2220000' +@dateTimes45='1970-09-03T12:00:00.0000000' (Scale = 1) +@dateTimes46='1971-09-03T12:00:10.2200000' (Scale = 1) +@dateTimes47='1972-09-03T12:00:10.3330000' (Scale = 1) +@dateTimes48='1973-09-03T12:00:10.0000000' (Scale = 1) +@dateTimes49='1974-09-03T12:00:10.5000000' (Scale = 1) +@dateTimes50='1975-09-03T12:00:10.6600000' (Scale = 1) +@dateTimes51='1976-09-03T12:00:10.7770000' (Scale = 1) +@dateTimes52='1977-09-03T12:00:10.8880000' (Scale = 1) +@dateTimes53='1978-09-03T12:00:10.9990000' (Scale = 1) +@dateTimes54='1979-09-03T12:00:10.1110000' (Scale = 1) +@dateTimes55='1980-09-03T12:00:10.2220000' (Scale = 1) +@dateTimes56='1970-09-03T12:00:00.0000000' (Scale = 2) +@dateTimes57='1971-09-03T12:00:10.2200000' (Scale = 2) +@dateTimes58='1972-09-03T12:00:10.3330000' (Scale = 2) +@dateTimes59='1973-09-03T12:00:10.0000000' (Scale = 2) +@dateTimes60='1974-09-03T12:00:10.5000000' (Scale = 2) +@dateTimes61='1975-09-03T12:00:10.6600000' (Scale = 2) +@dateTimes62='1976-09-03T12:00:10.7770000' (Scale = 2) +@dateTimes63='1977-09-03T12:00:10.8880000' (Scale = 2) +@dateTimes64='1978-09-03T12:00:10.9990000' (Scale = 2) +@dateTimes65='1979-09-03T12:00:10.1110000' (Scale = 2) +@dateTimes66='1980-09-03T12:00:10.2220000' (Scale = 2) +@dateTimes67='1970-09-03T12:00:00.0000000' (Scale = 3) +@dateTimes68='1971-09-03T12:00:10.2200000' (Scale = 3) +@dateTimes69='1972-09-03T12:00:10.3330000' (Scale = 3) +@dateTimes70='1973-09-03T12:00:10.0000000' (Scale = 3) +@dateTimes71='1974-09-03T12:00:10.5000000' (Scale = 3) +@dateTimes72='1975-09-03T12:00:10.6600000' (Scale = 3) +@dateTimes73='1976-09-03T12:00:10.7770000' (Scale = 3) +@dateTimes74='1977-09-03T12:00:10.8880000' (Scale = 3) +@dateTimes75='1978-09-03T12:00:10.9990000' (Scale = 3) +@dateTimes76='1979-09-03T12:00:10.1110000' (Scale = 3) +@dateTimes77='1980-09-03T12:00:10.2220000' (Scale = 3) +@dateTimes78='1970-09-03T12:00:00.0000000' (Scale = 4) +@dateTimes79='1971-09-03T12:00:10.2200000' (Scale = 4) +@dateTimes80='1972-09-03T12:00:10.3330000' (Scale = 4) +@dateTimes81='1973-09-03T12:00:10.0000000' (Scale = 4) +@dateTimes82='1974-09-03T12:00:10.5000000' (Scale = 4) +@dateTimes83='1975-09-03T12:00:10.6600000' (Scale = 4) +@dateTimes84='1976-09-03T12:00:10.7770000' (Scale = 4) +@dateTimes85='1977-09-03T12:00:10.8880000' (Scale = 4) +@dateTimes86='1978-09-03T12:00:10.9990000' (Scale = 4) +@dateTimes87='1979-09-03T12:00:10.1110000' (Scale = 4) +@dateTimes88='1980-09-03T12:00:10.2220000' (Scale = 4) +@dateTimes89='1970-09-03T12:00:00.0000000' (Scale = 5) +@dateTimes90='1971-09-03T12:00:10.2200000' (Scale = 5) +@dateTimes91='1972-09-03T12:00:10.3330000' (Scale = 5) +@dateTimes92='1973-09-03T12:00:10.0000000' (Scale = 5) +@dateTimes93='1974-09-03T12:00:10.5000000' (Scale = 5) +@dateTimes94='1975-09-03T12:00:10.6600000' (Scale = 5) +@dateTimes95='1976-09-03T12:00:10.7770000' (Scale = 5) +@dateTimes96='1977-09-03T12:00:10.8880000' (Scale = 5) +@dateTimes97='1978-09-03T12:00:10.9990000' (Scale = 5) +@dateTimes98='1979-09-03T12:00:10.1110000' (Scale = 5) +@dateTimes99='1980-09-03T12:00:10.2220000' (Scale = 5) +@dateTimes100='1970-09-03T12:00:00.0000000' (Scale = 6) +@dateTimes101='1971-09-03T12:00:10.2200000' (Scale = 6) +@dateTimes102='1972-09-03T12:00:10.3330000' (Scale = 6) +@dateTimes103='1973-09-03T12:00:10.0000000' (Scale = 6) +@dateTimes104='1974-09-03T12:00:10.5000000' (Scale = 6) +@dateTimes105='1975-09-03T12:00:10.6600000' (Scale = 6) +@dateTimes106='1976-09-03T12:00:10.7770000' (Scale = 6) +@dateTimes107='1977-09-03T12:00:10.8880000' (Scale = 6) +@dateTimes108='1978-09-03T12:00:10.9990000' (Scale = 6) +@dateTimes109='1979-09-03T12:00:10.1110000' (Scale = 6) +@dateTimes110='1980-09-03T12:00:10.2220000' (Scale = 6) +@dateTimes111='1970-09-03T12:00:00.0000000' (Scale = 7) +@dateTimes112='1971-09-03T12:00:10.2200000' (Scale = 7) +@dateTimes113='1972-09-03T12:00:10.3330000' (Scale = 7) +@dateTimes114='1973-09-03T12:00:10.0000000' (Scale = 7) +@dateTimes115='1974-09-03T12:00:10.5000000' (Scale = 7) +@dateTimes116='1975-09-03T12:00:10.6600000' (Scale = 7) +@dateTimes117='1976-09-03T12:00:10.7770000' (Scale = 7) +@dateTimes118='1977-09-03T12:00:10.8880000' (Scale = 7) +@dateTimes119='1978-09-03T12:00:10.9990000' (Scale = 7) +@dateTimes120='1979-09-03T12:00:10.1110000' (Scale = 7) +@dateTimes121='1980-09-03T12:00:10.2220000' (Scale = 7) SELECT [d].[Id], [d].[DateTime], [d].[DateTime2], [d].[DateTime2_0], [d].[DateTime2_1], [d].[DateTime2_2], [d].[DateTime2_3], [d].[DateTime2_4], [d].[DateTime2_5], [d].[DateTime2_6], [d].[DateTime2_7], [d].[SmallDateTime] FROM [Dates] AS [d] -WHERE [d].[SmallDateTime] IN ( - SELECT [d0].[value] - FROM OPENJSON(@dateTimes) WITH ([value] smalldatetime '$') AS [d0] -) AND [d].[DateTime] IN ( - SELECT [d1].[value] - FROM OPENJSON(@dateTimes0) WITH ([value] datetime '$') AS [d1] -) AND [d].[DateTime2] IN ( - SELECT [d2].[value] - FROM OPENJSON(@dateTimes1) WITH ([value] datetime2 '$') AS [d2] -) AND [d].[DateTime2_0] IN ( - SELECT [d3].[value] - FROM OPENJSON(@dateTimes2) WITH ([value] datetime2(0) '$') AS [d3] -) AND [d].[DateTime2_1] IN ( - SELECT [d4].[value] - FROM OPENJSON(@dateTimes3) WITH ([value] datetime2(1) '$') AS [d4] -) AND [d].[DateTime2_2] IN ( - SELECT [d5].[value] - FROM OPENJSON(@dateTimes4) WITH ([value] datetime2(2) '$') AS [d5] -) AND [d].[DateTime2_3] IN ( - SELECT [d6].[value] - FROM OPENJSON(@dateTimes5) WITH ([value] datetime2(3) '$') AS [d6] -) AND [d].[DateTime2_4] IN ( - SELECT [d7].[value] - FROM OPENJSON(@dateTimes6) WITH ([value] datetime2(4) '$') AS [d7] -) AND [d].[DateTime2_5] IN ( - SELECT [d8].[value] - FROM OPENJSON(@dateTimes7) WITH ([value] datetime2(5) '$') AS [d8] -) AND [d].[DateTime2_6] IN ( - SELECT [d9].[value] - FROM OPENJSON(@dateTimes8) WITH ([value] datetime2(6) '$') AS [d9] -) AND [d].[DateTime2_7] IN ( - SELECT [d10].[value] - FROM OPENJSON(@dateTimes9) WITH ([value] datetime2(7) '$') AS [d10] -) +WHERE [d].[SmallDateTime] IN (@dateTimes1, @dateTimes2, @dateTimes3, @dateTimes4, @dateTimes5, @dateTimes6, @dateTimes7, @dateTimes8, @dateTimes9, @dateTimes10, @dateTimes11) AND [d].[DateTime] IN (@dateTimes12, @dateTimes13, @dateTimes14, @dateTimes15, @dateTimes16, @dateTimes17, @dateTimes18, @dateTimes19, @dateTimes20, @dateTimes21, @dateTimes22) AND [d].[DateTime2] IN (@dateTimes23, @dateTimes24, @dateTimes25, @dateTimes26, @dateTimes27, @dateTimes28, @dateTimes29, @dateTimes30, @dateTimes31, @dateTimes32, @dateTimes33) AND [d].[DateTime2_0] IN (@dateTimes34, @dateTimes35, @dateTimes36, @dateTimes37, @dateTimes38, @dateTimes39, @dateTimes40, @dateTimes41, @dateTimes42, @dateTimes43, @dateTimes44) AND [d].[DateTime2_1] IN (@dateTimes45, @dateTimes46, @dateTimes47, @dateTimes48, @dateTimes49, @dateTimes50, @dateTimes51, @dateTimes52, @dateTimes53, @dateTimes54, @dateTimes55) AND [d].[DateTime2_2] IN (@dateTimes56, @dateTimes57, @dateTimes58, @dateTimes59, @dateTimes60, @dateTimes61, @dateTimes62, @dateTimes63, @dateTimes64, @dateTimes65, @dateTimes66) AND [d].[DateTime2_3] IN (@dateTimes67, @dateTimes68, @dateTimes69, @dateTimes70, @dateTimes71, @dateTimes72, @dateTimes73, @dateTimes74, @dateTimes75, @dateTimes76, @dateTimes77) AND [d].[DateTime2_4] IN (@dateTimes78, @dateTimes79, @dateTimes80, @dateTimes81, @dateTimes82, @dateTimes83, @dateTimes84, @dateTimes85, @dateTimes86, @dateTimes87, @dateTimes88) AND [d].[DateTime2_5] IN (@dateTimes89, @dateTimes90, @dateTimes91, @dateTimes92, @dateTimes93, @dateTimes94, @dateTimes95, @dateTimes96, @dateTimes97, @dateTimes98, @dateTimes99) AND [d].[DateTime2_6] IN (@dateTimes100, @dateTimes101, @dateTimes102, @dateTimes103, @dateTimes104, @dateTimes105, @dateTimes106, @dateTimes107, @dateTimes108, @dateTimes109, @dateTimes110) AND [d].[DateTime2_7] IN (@dateTimes111, @dateTimes112, @dateTimes113, @dateTimes114, @dateTimes115, @dateTimes116, @dateTimes117, @dateTimes118, @dateTimes119, @dateTimes120, @dateTimes121) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocQueryFiltersQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocQueryFiltersQuerySqlServerTest.cs index 4b4e8478108..d2e44796c43 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocQueryFiltersQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocQueryFiltersQuerySqlServerTest.cs @@ -30,14 +30,12 @@ public override async Task Named_query_filters_anonymous() AssertSql( """ -@ef_filter___ids='[1,7]' (Size = 4000) +@ef_filter___ids1='1' +@ef_filter___ids2='7' SELECT [e].[Id], [e].[IsDeleted], [e].[IsDraft], [e].[Name] FROM [Entities] AS [e] -WHERE [e].[Id] NOT IN ( - SELECT [e0].[value] - FROM OPENJSON(@ef_filter___ids) WITH ([value] int '$') AS [e0] -) +WHERE [e].[Id] NOT IN (@ef_filter___ids1, @ef_filter___ids2) """); } @@ -217,14 +215,12 @@ public override async Task Query_filter_with_contains_evaluates_correctly() AssertSql( """ -@ef_filter___ids='[1,7]' (Size = 4000) +@ef_filter___ids1='1' +@ef_filter___ids2='7' SELECT [e].[Id], [e].[Name] FROM [Entities] AS [e] -WHERE [e].[Id] NOT IN ( - SELECT [e0].[value] - FROM OPENJSON(@ef_filter___ids) WITH ([value] int '$') AS [e0] -) +WHERE [e].[Id] NOT IN (@ef_filter___ids1, @ef_filter___ids2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs index c3cfee30c00..4a123693a67 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs @@ -1216,7 +1216,8 @@ public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_coll AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT CASE WHEN [l0].[Id] IS NULL THEN 0 @@ -1225,10 +1226,7 @@ ELSE [l0].[Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToMany_Required_Inverse3Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) ORDER BY [l].[Id], [l0].[Id] """); } @@ -2332,25 +2330,20 @@ public override async Task Collection_projection_over_GroupBy_over_parameter(boo AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT [l1].[Date], [l2].[Id] FROM ( SELECT [l].[Date] FROM [LevelOne] AS [l] - WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] - ) + WHERE [l].[Name] IN (@validIds1, @validIds2) GROUP BY [l].[Date] ) AS [l1] LEFT JOIN ( SELECT [l0].[Id], [l0].[Date] FROM [LevelOne] AS [l0] - WHERE [l0].[Name] IN ( - SELECT [v0].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v0] - ) + WHERE [l0].[Name] IN (@validIds1, @validIds2) ) AS [l2] ON [l1].[Date] = [l2].[Date] ORDER BY [l1].[Date] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs index 7b7307b6702..e16f2167ea3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs @@ -2846,7 +2846,8 @@ public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_coll AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT CASE WHEN [s].[OneToOne_Required_PK_Date] IS NULL OR [s].[Level1_Required_Id] IS NULL OR [s].[OneToMany_Required_Inverse2Id] IS NULL THEN 0 @@ -2872,10 +2873,7 @@ WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse ) AS [l4] ON CASE WHEN [s].[OneToOne_Required_PK_Date] IS NOT NULL AND [s].[Level1_Required_Id] IS NOT NULL AND [s].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [s].[Id0] END = [l4].[OneToMany_Required_Inverse3Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) ORDER BY [l].[Id], [s].[Id], [s].[Id0] """); } @@ -3012,25 +3010,20 @@ public override async Task Collection_projection_over_GroupBy_over_parameter(boo AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT [l1].[Date], [l2].[Id] FROM ( SELECT [l].[Date] FROM [Level1] AS [l] - WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] - ) + WHERE [l].[Name] IN (@validIds1, @validIds2) GROUP BY [l].[Date] ) AS [l1] LEFT JOIN ( SELECT [l0].[Id], [l0].[Date] FROM [Level1] AS [l0] - WHERE [l0].[Name] IN ( - SELECT [v0].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v0] - ) + WHERE [l0].[Name] IN (@validIds1, @validIds2) ) AS [l2] ON [l1].[Date] = [l2].[Date] ORDER BY [l1].[Date] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs index 944f4f73611..3289427b405 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs @@ -3189,7 +3189,8 @@ public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_coll AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT CASE WHEN [l0].[Id] IS NULL THEN 0 @@ -3197,24 +3198,19 @@ ELSE [l0].[Id] END, [l].[Id], [l0].[Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) ORDER BY [l].[Id], [l0].[Id] """, // """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds3='L1 01' (Size = 4000) +@validIds4='L1 02' (Size = 4000) SELECT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [l].[Id], [l0].[Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] INNER JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToMany_Required_Inverse3Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds3, @validIds4) ORDER BY [l].[Id], [l0].[Id] """); } @@ -3747,38 +3743,31 @@ public override async Task Collection_projection_over_GroupBy_over_parameter(boo AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT [l].[Date] FROM [LevelOne] AS [l] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) GROUP BY [l].[Date] ORDER BY [l].[Date] """, // """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds3='L1 01' (Size = 4000) +@validIds4='L1 02' (Size = 4000) SELECT [l5].[Id], [l4].[Date] FROM ( SELECT [l].[Date] FROM [LevelOne] AS [l] - WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] - ) + WHERE [l].[Name] IN (@validIds3, @validIds4) GROUP BY [l].[Date] ) AS [l4] INNER JOIN ( SELECT [l3].[Id], [l3].[Date] FROM [LevelOne] AS [l3] - WHERE [l3].[Name] IN ( - SELECT [v3].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v3] - ) + WHERE [l3].[Name] IN (@validIds3, @validIds4) ) AS [l5] ON [l4].[Date] = [l5].[Date] ORDER BY [l4].[Date] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs index ac99bc66a48..2d15be82d36 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs @@ -3137,15 +3137,13 @@ public override async Task Accessing_optional_property_inside_result_operator_su AssertSql( """ -@names='["Name1","Name2"]' (Size = 4000) +@names1='Name1' (Size = 4000) +@names2='Name2' (Size = 4000) SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE [l0].[Name] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) OR [l0].[Name] IS NULL +WHERE [l0].[Name] NOT IN (@names1, @names2) OR [l0].[Name] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index f83642771d0..30a3b59429b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -3137,15 +3137,13 @@ public override async Task Accessing_optional_property_inside_result_operator_su AssertSql( """ -@names='["Name1","Name2"]' (Size = 4000) +@names1='Name1' (Size = 4000) +@names2='Name2' (Size = 4000) SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] -WHERE [l0].[Name] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) OR [l0].[Name] IS NULL +WHERE [l0].[Name] NOT IN (@names1, @names2) OR [l0].[Name] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs index 3684de4c46d..94c82687614 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs @@ -5568,7 +5568,8 @@ public override async Task Accessing_optional_property_inside_result_operator_su AssertSql( """ -@names='["Name1","Name2"]' (Size = 4000) +@names1='Name1' (Size = 4000) +@names2='Name2' (Size = 4000) SELECT [l].[Id], [l].[Date], [l].[Name] FROM [Level1] AS [l] @@ -5577,10 +5578,7 @@ LEFT JOIN ( FROM [Level1] AS [l0] WHERE [l0].[OneToOne_Required_PK_Date] IS NOT NULL AND [l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL ) AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] -WHERE [l1].[Level2_Name] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) OR [l1].[Level2_Name] IS NULL +WHERE [l1].[Level2_Name] NOT IN (@names1, @names2) OR [l1].[Level2_Name] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs index bc2096eeb2c..cae64591838 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs @@ -5570,7 +5570,8 @@ public override async Task Accessing_optional_property_inside_result_operator_su AssertSql( """ -@names='["Name1","Name2"]' (Size = 4000) +@names1='Name1' (Size = 4000) +@names2='Name2' (Size = 4000) SELECT [l].[Id], [l].[Date], [l].[Name] FROM [Level1] AS [l] @@ -5579,10 +5580,7 @@ LEFT JOIN ( FROM [Level1] AS [l0] WHERE [l0].[OneToOne_Required_PK_Date] IS NOT NULL AND [l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL ) AS [l1] ON [l].[Id] = [l1].[Level1_Optional_Id] -WHERE [l1].[Level2_Name] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) OR [l1].[Level2_Name] IS NULL +WHERE [l1].[Level2_Name] NOT IN (@names1, @names2) OR [l1].[Level2_Name] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 23d22236769..5046a266b59 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -208,15 +208,17 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -231,16 +233,18 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -255,15 +259,17 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' 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] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -1759,14 +1765,12 @@ public override async Task Non_unicode_string_literals_in_contains_is_used_for_n AssertSql( """ -@cities='["Unknown","Jacinto\u0027s location","Ephyra\u0027s location"]' (Size = 4000) +@cities1='Unknown' (Size = 100) (DbType = AnsiString) +@cities2='Jacinto's location' (Size = 100) (DbType = AnsiString), @cities3='Ephyra's location' (Size = 100) (DbType = AnsiString) SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE [c].[Location] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] varchar(100) '$') AS [c0] -) +WHERE [c].[Location] IN (@cities1, @cities2, @cities3) """); } @@ -2555,14 +2559,13 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a AssertSql( """ -@ids='["df36f493-463f-4123-83f9-6b135deeb7ba","23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3","ab1b82d7-88db-42bd-a132-7eef9aa68af4"]' (Size = 4000) +@ids1='df36f493-463f-4123-83f9-6b135deeb7ba' +@ids2='23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3' +@ids3='ab1b82d7-88db-42bd-a132-7eef9aa68af4' SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM [Tags] AS [t] -WHERE [t].[Id] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] uniqueidentifier '$') AS [i] -) +WHERE [t].[Id] IN (@ids1, @ids2, @ids3) """); } @@ -3078,15 +3081,12 @@ public override async Task Contains_on_nullable_array_produces_correct_sql(bool AssertSql( """ -@cities_without_nulls='["Ephyra"]' (Size = 4000) +@cities1='Ephyra' (Size = 450) 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] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] -WHERE [g].[SquadId] < 2 AND ([c].[Name] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities_without_nulls) AS [c0] -) OR [c].[Name] IS NULL) +WHERE [g].[SquadId] < 2 AND ([c].[Name] IS NULL OR [c].[Name] = @cities1) """); } @@ -5450,18 +5450,10 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz AssertSql( """ -@nicknames='[]' (Size = 4000) - SELECT [g].[Nickname], [g].[SquadId], [w].[Name], [w].[Id] FROM [Gears] AS [g] LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] -ORDER BY CASE - WHEN [g].[Nickname] IN ( - SELECT [n].[value] - FROM OPENJSON(@nicknames) WITH ([value] nvarchar(450) '$') AS [n] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END DESC, [g].[Nickname], [g].[SquadId] +ORDER BY [g].[Nickname], [g].[SquadId] """); } @@ -6142,14 +6134,11 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a """ @start='1902-01-01T10:00:00.1234567+01:30' @end='1902-01-03T10:00:00.1234567+01:30' -@dates='["1902-01-02T10:00:00.1234567+01:30"]' (Size = 4000) +@dates1='1902-01-02T10:00:00.1234567+01:30' SELECT [m].[Id], [m].[BriefingDocument], [m].[BriefingDocumentFileExtension], [m].[CodeName], [m].[Date], [m].[Difficulty], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline] FROM [Missions] AS [m] -WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetimeoffset '$') AS [d] -) +WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] = @dates1 """); } @@ -6858,17 +6847,8 @@ public override async Task OrderBy_Contains_empty_list(bool async) AssertSql( """ -@ids='[]' (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] -ORDER BY CASE - WHEN [g].[SquadId] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -7419,15 +7399,12 @@ public override async Task Enum_array_contains(bool async) AssertSql( """ -@types_without_nulls='[1]' (Size = 4000) +@types1='1' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] LEFT JOIN [Weapons] AS [w0] ON [w].[SynergyWithId] = [w0].[Id] -WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IN ( - SELECT [t].[value] - FROM OPENJSON(@types_without_nulls) AS [t] -) OR [w0].[AmmunitionType] IS NULL) +WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IS NULL OR [w0].[AmmunitionType] = @types1) """); } @@ -8444,14 +8421,12 @@ public override async Task Where_bool_column_and_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -8461,14 +8436,12 @@ public override async Task Where_bool_column_or_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -9156,7 +9129,8 @@ public override async Task Nav_expansion_inside_Contains_argument(bool async) AssertSql( """ -@numbers='[1,-1]' (Size = 4000) +@numbers1='1' +@numbers2='-1' 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] @@ -9166,10 +9140,7 @@ SELECT 1 FROM [Weapons] AS [w] WHERE [g].[FullName] = [w].[OwnerFullName]) THEN 1 ELSE 0 -END IN ( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] -) +END IN (@numbers1, @numbers2) """); } @@ -9179,18 +9150,15 @@ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_ar AssertSql( """ -@weapons='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000) +@weapons1='Marcus' Lancer' (Size = 4000), @weapons2='Dom's 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 ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] AS [w0] - WHERE [g].[FullName] = [w0].[OwnerFullName] - ORDER BY [w0].[Id]) IN ( - SELECT [w].[value] - FROM OPENJSON(@weapons) WITH ([value] nvarchar(max) '$') AS [w] -) + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [g].[FullName] = [w].[OwnerFullName] + ORDER BY [w].[Id]) IN (@weapons1, @weapons2) """); } @@ -9200,7 +9168,9 @@ public override async Task Subquery_inside_Take_argument(bool async) AssertSql( """ -@numbers='[0,1,2]' (Size = 4000) +@numbers1='0' +@numbers2='1' +@numbers3='2' SELECT [g].[Nickname], [g].[SquadId], [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId] FROM [Gears] AS [g] @@ -9211,9 +9181,9 @@ LEFT JOIN ( FROM [Weapons] AS [w] ) AS [w0] WHERE [w0].[row] <= ISNULL(( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] - ORDER BY [n].[value] + SELECT [n].[Value] + FROM (VALUES (1, @numbers1), (2, @numbers2), (3, @numbers3)) AS [n]([_ord], [Value]) + ORDER BY [n].[Value] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0) ) AS [w1] ON [g].[FullName] = [w1].[OwnerFullName] ORDER BY [g].[Nickname], [g].[SquadId], [w1].[OwnerFullName], [w1].[Id] @@ -9376,41 +9346,31 @@ public override async Task Nested_contains_with_enum(bool async) AssertSql( """ -@ranks='[1]' (Size = 4000) +@ranks1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' 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 [g].[Rank] IN ( - SELECT [r].[value] - FROM OPENJSON(@ranks) WITH ([value] int '$') AS [r] - ) THEN @key + WHEN [g].[Rank] = @ranks1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """, // """ -@ammoTypes='[1]' (Size = 4000) +@ammoTypes1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] WHERE CASE - WHEN [w].[AmmunitionType] IN ( - SELECT [a].[value] - FROM OPENJSON(@ammoTypes) WITH ([value] int '$') AS [a] - ) THEN @key + WHEN [w].[AmmunitionType] = @ammoTypes1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs index 9429b192485..3016f7c7b93 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs @@ -10,16 +10,9 @@ namespace Microsoft.EntityFrameworkCore.Query; public class NonSharedPrimitiveCollectionsQuerySqlServerTest(NonSharedFixture fixture) : NonSharedPrimitiveCollectionsQueryRelationalTestBase(fixture) { - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) { - new SqlServerDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); - - return optionsBuilder; - } - - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToParameters(DbContextOptionsBuilder optionsBuilder) - { - new SqlServerDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToParameters(); + new SqlServerDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); return optionsBuilder; } @@ -807,9 +800,9 @@ SELECT COUNT(*) """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_constants() + public override async Task Parameter_collection_Contains_with_default_constants() { - await base.Parameter_collection_of_ints_Contains_int_with_default_constants(); + await base.Parameter_collection_Contains_with_default_constants(); AssertSql( """ @@ -836,9 +829,9 @@ FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_constants_EF_Parameter() + public override async Task Parameter_collection_Contains_with_default_constants_EF_Parameter() { - await base.Parameter_collection_of_ints_Contains_int_with_default_constants_EF_Parameter(); + await base.Parameter_collection_Contains_with_default_constants_EF_Parameter(); AssertSql( """ @@ -853,9 +846,9 @@ FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] """); } - public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameters() + public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameter() { - await base.Parameter_collection_Count_with_column_predicate_with_default_parameters(); + await base.Parameter_collection_Count_with_column_predicate_with_default_parameter(); AssertSql( """ @@ -870,9 +863,9 @@ FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_parameters() + public override async Task Parameter_collection_Contains_with_default_parameter() { - await base.Parameter_collection_of_ints_Contains_int_with_default_parameters(); + await base.Parameter_collection_Contains_with_default_parameter(); AssertSql( """ @@ -887,9 +880,9 @@ FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] """); } - public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameters_EF_Constant() + public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameter_EF_Constant() { - await base.Parameter_collection_Count_with_column_predicate_with_default_parameters_EF_Constant(); + await base.Parameter_collection_Count_with_column_predicate_with_default_parameter_EF_Constant(); AssertSql( """ @@ -902,9 +895,9 @@ SELECT COUNT(*) """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_parameters_EF_Constant() + public override async Task Parameter_collection_Contains_with_default_parameter_EF_Constant() { - await base.Parameter_collection_of_ints_Contains_int_with_default_parameters_EF_Constant(); + await base.Parameter_collection_Contains_with_default_parameter_EF_Constant(); AssertSql( """ @@ -914,6 +907,39 @@ WHERE [t].[Id] IN (2, 999) """); } + public override async Task Parameter_collection_Count_with_column_predicate_with_default_multiple_parameters() + { + await base.Parameter_collection_Count_with_column_predicate_with_default_multiple_parameters(); + + AssertSql( + """ +@ids1='2' +@ids2='999' + +SELECT [t].[Id] +FROM [TestEntity] AS [t] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (@ids1), (@ids2)) AS [i]([Value]) + WHERE [i].[Value] > [t].[Id]) = 1 +"""); + } + + public override async Task Parameter_collection_Contains_with_default_multiple_parameters() + { + await base.Parameter_collection_Contains_with_default_multiple_parameters(); + + AssertSql( + """ +@ints1='2' +@ints2='999' + +SELECT [t].[Id] +FROM [TestEntity] AS [t] +WHERE [t].[Id] IN (@ints1, @ints2) +"""); + } + [ConditionalFact] public virtual async Task Same_parameter_with_different_type_mappings() { @@ -938,18 +964,14 @@ public virtual async Task Same_parameter_with_different_type_mappings() AssertSql( """ -@dateTimes='["2020-01-01T12:30:00","2020-01-02T12:30:00"]' (Size = 4000) -@dateTimes0='["2020-01-01T12:30:00","2020-01-02T12:30:00"]' (Size = 4000) +@dateTimes1='2020-01-01T12:30:00.0000000' (DbType = DateTime) +@dateTimes2='2020-01-02T12:30:00.0000000' (DbType = DateTime) +@dateTimes3='2020-01-01T12:30:00.0000000' +@dateTimes4='2020-01-02T12:30:00.0000000' SELECT [t].[Id], [t].[DateTime], [t].[DateTime2], [t].[Ints] FROM [TestEntity] AS [t] -WHERE [t].[DateTime] IN ( - SELECT [d].[value] - FROM OPENJSON(@dateTimes) WITH ([value] datetime '$') AS [d] -) AND [t].[DateTime2] IN ( - SELECT [d0].[value] - FROM OPENJSON(@dateTimes0) WITH ([value] datetime2 '$') AS [d0] -) +WHERE [t].[DateTime] IN (@dateTimes1, @dateTimes2) AND [t].[DateTime2] IN (@dateTimes3, @dateTimes4) """); } @@ -969,14 +991,16 @@ public virtual async Task Same_collection_with_default_type_mapping_and_uninferr AssertSql( """ -@dateTimes='["2020-01-01T12:30:00","2020-01-02T12:30:00",null]' (Size = 4000) +@dateTimes1='2020-01-01T12:30:00.0000000' +@dateTimes2='2020-01-02T12:30:00.0000000' +@dateTimes3=NULL (DbType = DateTime2) SELECT [t].[Id], [t].[DateTime], [t].[Ints] FROM [TestEntity] AS [t] WHERE EXISTS ( SELECT 1 - FROM OPENJSON(@dateTimes) WITH ([value] datetime2 '$') AS [d] - WHERE [d].[value] = [t].[DateTime] AND [d].[value] IS NOT NULL) + FROM (VALUES (@dateTimes1), (@dateTimes2), (@dateTimes3)) AS [d]([Value]) + WHERE [d].[Value] = [t].[DateTime] AND [d].[Value] IS NOT NULL) """); } @@ -996,7 +1020,7 @@ public virtual async Task Same_collection_with_non_default_type_mapping_and_unin .Where( m => dateTimes.Any(d => d == EF.Property(m, "DateTime") && d != null)) .ToArrayAsync()); - Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("value"), exception.Message); + Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("Value"), exception.Message); } [ConditionalFact] @@ -1020,7 +1044,7 @@ public virtual async Task Same_collection_with_conflicting_type_mappings_not_sup m => dateTimes .Any(d => d == EF.Property(m, "DateTime") && d == EF.Property(m, "DateTime2"))) .ToArrayAsync()); - Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("value"), exception.Message); + Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("Value"), exception.Message); } [ConditionalFact] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs index 0e6da7bd487..1211206d00e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs @@ -1629,25 +1629,20 @@ public override async Task Contains_with_local_array_closure(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """, // """ -@ids='["ABCDE"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -1657,31 +1652,26 @@ public override async Task Contains_with_subquery_and_local_array_closure(bool a AssertSql( """ -@ids='["London","Buenos Aires"]' (Size = 4000) +@ids1='London' (Size = 15) +@ids2='Buenos Aires' (Size = 15) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Customers] AS [c0] - WHERE [c0].[City] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nvarchar(15) '$') AS [i] - ) AND [c0].[CustomerID] = [c].[CustomerID]) + WHERE [c0].[City] IN (@ids1, @ids2) AND [c0].[CustomerID] = [c].[CustomerID]) """, // """ -@ids='["London"]' (Size = 4000) +@ids1='London' (Size = 15) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE EXISTS ( SELECT 1 FROM [Customers] AS [c0] - WHERE [c0].[City] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nvarchar(15) '$') AS [i] - ) AND [c0].[CustomerID] = [c].[CustomerID]) + WHERE [c0].[City] = @ids1 AND [c0].[CustomerID] = [c].[CustomerID]) """); } @@ -1691,25 +1681,20 @@ public override async Task Contains_with_local_uint_array_closure(bool async) AssertSql( """ -@ids='[0,1]' (Size = 4000) +@ids1='0' +@ids2='1' SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE [e].[EmployeeID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[EmployeeID] IN (@ids1, @ids2) """, // """ -@ids='[0]' (Size = 4000) +@ids1='0' SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE [e].[EmployeeID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[EmployeeID] = @ids1 """); } @@ -1719,25 +1704,20 @@ public override async Task Contains_with_local_nullable_uint_array_closure(bool AssertSql( """ -@ids='[0,1]' (Size = 4000) +@ids1='0' +@ids2='1' SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE [e].[EmployeeID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[EmployeeID] IN (@ids1, @ids2) """, // """ -@ids='[0]' (Size = 4000) +@ids1='0' SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] -WHERE [e].[EmployeeID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[EmployeeID] = @ids1 """); } @@ -1759,14 +1739,12 @@ public override async Task Contains_with_local_list_closure(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -1776,14 +1754,12 @@ public override async Task Contains_with_local_object_list_closure(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -1793,14 +1769,9 @@ public override async Task Contains_with_local_list_closure_all_null(bool async) AssertSql( """ -@ids='[null,null]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE 0 = 1 """); } @@ -1822,25 +1793,21 @@ public override async Task Contains_with_local_list_inline_closure_mix(bool asyn AssertSql( """ -@p='["ABCDE","ALFKI"]' (Size = 4000) +@p1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@p2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [p].[value] - FROM OPENJSON(@p) WITH ([value] nchar(5) '$') AS [p] -) +WHERE [c].[CustomerID] IN (@p1, @p2) """, // """ -@p='["ABCDE","ANATR"]' (Size = 4000) +@p1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@p2='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [p].[value] - FROM OPENJSON(@p) WITH ([value] nchar(5) '$') AS [p] -) +WHERE [c].[CustomerID] IN (@p1, @p2) """); } @@ -1850,25 +1817,21 @@ public override async Task Contains_with_local_non_primitive_list_inline_closure AssertSql( """ -@Select='["ABCDE","ALFKI"]' (Size = 4000) +@Select1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@Select2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [s].[value] - FROM OPENJSON(@Select) WITH ([value] nchar(5) '$') AS [s] -) +WHERE [c].[CustomerID] IN (@Select1, @Select2) """, // """ -@Select='["ABCDE","ANATR"]' (Size = 4000) +@Select1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@Select2='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [s].[value] - FROM OPENJSON(@Select) WITH ([value] nchar(5) '$') AS [s] -) +WHERE [c].[CustomerID] IN (@Select1, @Select2) """); } @@ -1878,25 +1841,20 @@ public override async Task Contains_with_local_enumerable_closure(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """, // """ -@ids='["ABCDE"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -1906,14 +1864,12 @@ public override async Task Contains_with_local_object_enumerable_closure(bool as AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -1923,14 +1879,9 @@ public override async Task Contains_with_local_enumerable_closure_all_null(bool AssertSql( """ -@ids='[]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE 0 = 1 """); } @@ -1960,25 +1911,20 @@ public override async Task Contains_with_local_ordered_enumerable_closure(bool a AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """, // """ -@ids='["ABCDE"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -1988,14 +1934,12 @@ public override async Task Contains_with_local_object_ordered_enumerable_closure AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -2005,14 +1949,9 @@ public override async Task Contains_with_local_ordered_enumerable_closure_all_nu AssertSql( """ -@ids='[null,null]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE 0 = 1 """); } @@ -2034,25 +1973,21 @@ public override async Task Contains_with_local_ordered_enumerable_inline_closure AssertSql( """ -@Order='["ABCDE","ALFKI"]' (Size = 4000) +@Order1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@Order2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [o].[value] - FROM OPENJSON(@Order) WITH ([value] nchar(5) '$') AS [o] -) +WHERE [c].[CustomerID] IN (@Order1, @Order2) """, // """ -@Order='["ABCDE","ANATR"]' (Size = 4000) +@Order1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@Order2='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [o].[value] - FROM OPENJSON(@Order) WITH ([value] nchar(5) '$') AS [o] -) +WHERE [c].[CustomerID] IN (@Order1, @Order2) """); } @@ -2062,25 +1997,20 @@ public override async Task Contains_with_local_read_only_collection_closure(bool AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """, // """ -@ids='["ABCDE"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -2090,14 +2020,12 @@ public override async Task Contains_with_local_object_read_only_collection_closu AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -2107,14 +2035,9 @@ public override async Task Contains_with_local_ordered_read_only_collection_all_ AssertSql( """ -@ids='[null,null]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE 0 = 1 """); } @@ -2136,25 +2059,21 @@ public override async Task Contains_with_local_read_only_collection_inline_closu AssertSql( """ -@AsReadOnly='["ABCDE","ALFKI"]' (Size = 4000) +@AsReadOnly1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@AsReadOnly2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@AsReadOnly) WITH ([value] nchar(5) '$') AS [a] -) +WHERE [c].[CustomerID] IN (@AsReadOnly1, @AsReadOnly2) """, // """ -@AsReadOnly='["ABCDE","ANATR"]' (Size = 4000) +@AsReadOnly1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@AsReadOnly2='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@AsReadOnly) WITH ([value] nchar(5) '$') AS [a] -) +WHERE [c].[CustomerID] IN (@AsReadOnly1, @AsReadOnly2) """); } @@ -2164,14 +2083,12 @@ public override async Task Contains_with_local_non_primitive_list_closure_mix(bo AssertSql( """ -@Select='["ABCDE","ALFKI"]' (Size = 4000) +@Select1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@Select2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [s].[value] - FROM OPENJSON(@Select) WITH ([value] nchar(5) '$') AS [s] -) +WHERE [c].[CustomerID] IN (@Select1, @Select2) """); } @@ -2181,14 +2098,12 @@ public override async Task Contains_with_local_collection_false(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] NOT IN (@ids1, @ids2) """); } @@ -2198,14 +2113,12 @@ public override async Task Contains_with_local_collection_complex_predicate_and( AssertSql( """ -@ids='["ABCDE","ALFKI"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN (N'ALFKI', N'ABCDE') AND [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (N'ALFKI', N'ABCDE') AND [c].[CustomerID] IN (@ids1, @ids2) """); } @@ -2239,14 +2152,12 @@ public override async Task Contains_with_local_collection_sql_injection(bool asy AssertSql( """ -@ids='["ALFKI","ABC\u0027)); GO; DROP TABLE Orders; GO; --"]' (Size = 4000) +@ids1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids2='ABC')); GO; DROP TABLE Orders; GO; --' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) OR [c].[CustomerID] IN (N'ALFKI', N'ABCDE') +WHERE [c].[CustomerID] IN (@ids1, @ids2) OR [c].[CustomerID] IN (N'ALFKI', N'ABCDE') """); } @@ -2256,14 +2167,9 @@ public override async Task Contains_with_local_collection_empty_closure(bool asy AssertSql( """ -@ids='[]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE 0 = 1 """); } @@ -2461,9 +2367,12 @@ public override async Task List_Contains_with_parameter_list(bool async) AssertSql( """ +@entity_equality_customers_CustomerID1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@entity_equality_customers_CustomerID2='ANATR' (Size = 5) (DbType = StringFixedLength) + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN (N'ALFKI', N'ANATR') +WHERE [c].[CustomerID] IN (@entity_equality_customers_CustomerID1, @entity_equality_customers_CustomerID2) """); } @@ -2473,9 +2382,12 @@ public override async Task Contains_with_parameter_list_value_type_id(bool async AssertSql( """ +@entity_equality_orders_OrderID1='10248' +@entity_equality_orders_OrderID2='10249' + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[OrderID] IN (10248, 10249) +WHERE [o].[OrderID] IN (@entity_equality_orders_OrderID1, @entity_equality_orders_OrderID2) """); } @@ -2497,9 +2409,11 @@ public override async Task IImmutableSet_Contains_with_parameter(bool async) AssertSql( """ +@ids1='ALFKI' (Size = 5) (DbType = StringFixedLength) + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' +WHERE [c].[CustomerID] = @ids1 """); } @@ -2509,9 +2423,11 @@ public override async Task IReadOnlySet_Contains_with_parameter(bool async) AssertSql( """ +@ids1='ALFKI' (Size = 5) (DbType = StringFixedLength) + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' +WHERE [c].[CustomerID] = @ids1 """); } @@ -2521,14 +2437,11 @@ public override async Task HashSet_Contains_with_parameter(bool async) AssertSql( """ -@ids='["ALFKI"]' (Size = 4000) +@ids1='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -2538,14 +2451,11 @@ public override async Task ImmutableHashSet_Contains_with_parameter(bool async) AssertSql( """ -@ids='["ALFKI"]' (Size = 4000) +@ids1='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] = @ids1 """); } @@ -2723,14 +2633,13 @@ public override async Task Where_subquery_any_equals_operator(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2, @ids3) """); } @@ -2752,14 +2661,13 @@ public override async Task Where_subquery_any_equals_static(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] IN (@ids1, @ids2, @ids3) """); } @@ -2769,25 +2677,23 @@ public override async Task Where_subquery_where_any(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN (@ids1, @ids2, @ids3) """, // """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] IN (@ids1, @ids2, @ids3) """); } @@ -2797,14 +2703,13 @@ public override async Task Where_subquery_all_not_equals_operator(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] NOT IN (@ids1, @ids2, @ids3) """); } @@ -2826,14 +2731,13 @@ public override async Task Where_subquery_all_not_equals_static(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[CustomerID] NOT IN (@ids1, @ids2, @ids3) """); } @@ -2843,25 +2747,23 @@ public override async Task Where_subquery_where_all(bool async) AssertSql( """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] NOT IN (@ids1, @ids2, @ids3) """, // """ -@ids='["ABCDE","ALFKI","ANATR"]' (Size = 4000) +@ids1='ABCDE' (Size = 5) (DbType = StringFixedLength) +@ids2='ALFKI' (Size = 5) (DbType = StringFixedLength) +@ids3='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nchar(5) '$') AS [i] -) +WHERE [c].[City] = N'México D.F.' AND [c].[CustomerID] NOT IN (@ids1, @ids2, @ids3) """); } @@ -3026,18 +2928,13 @@ public override async Task Contains_inside_aggregate_function_with_GroupBy(bool AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) -SELECT COUNT([s].[value]) +SELECT COUNT(CASE + WHEN [c].[City] IN (@cities1, @cities2) THEN 1 +END) FROM [Customers] AS [c] -OUTER APPLY ( - SELECT CASE - WHEN [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] - ) THEN 1 - END AS [value] -) AS [s] GROUP BY [c].[Country] """); } @@ -3048,19 +2945,14 @@ public override async Task Contains_inside_Average_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) -SELECT AVG([s].[value]) +SELECT AVG(CASE + WHEN [c].[City] IN (@cities1, @cities2) THEN 1.0E0 + ELSE 0.0E0 +END) FROM [Customers] AS [c] -OUTER APPLY ( - SELECT CASE - WHEN [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] - ) THEN 1.0E0 - ELSE 0.0E0 - END AS [value] -) AS [s] """); } @@ -3070,19 +2962,14 @@ public override async Task Contains_inside_Sum_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) -SELECT ISNULL(SUM([s].[value]), 0) +SELECT ISNULL(SUM(CASE + WHEN [c].[City] IN (@cities1, @cities2) THEN 1 + ELSE 0 +END), 0) FROM [Customers] AS [c] -OUTER APPLY ( - SELECT CASE - WHEN [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] - ) THEN 1 - ELSE 0 - END AS [value] -) AS [s] """); } @@ -3092,14 +2979,12 @@ public override async Task Contains_inside_Count_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) SELECT COUNT(*) FROM [Customers] AS [c] -WHERE [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] -) +WHERE [c].[City] IN (@cities1, @cities2) """); } @@ -3109,14 +2994,12 @@ public override async Task Contains_inside_LongCount_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) SELECT COUNT_BIG(*) FROM [Customers] AS [c] -WHERE [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] -) +WHERE [c].[City] IN (@cities1, @cities2) """); } @@ -3126,19 +3009,14 @@ public override async Task Contains_inside_Max_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) -SELECT MAX([s].[value]) +SELECT MAX(CASE + WHEN [c].[City] IN (@cities1, @cities2) THEN 1 + ELSE 0 +END) FROM [Customers] AS [c] -OUTER APPLY ( - SELECT CASE - WHEN [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] - ) THEN 1 - ELSE 0 - END AS [value] -) AS [s] """); } @@ -3148,19 +3026,14 @@ public override async Task Contains_inside_Min_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 4000) +@cities1='London' (Size = 15) +@cities2='Berlin' (Size = 15) -SELECT MIN([s].[value]) +SELECT MIN(CASE + WHEN [c].[City] IN (@cities1, @cities2) THEN 1 + ELSE 0 +END) FROM [Customers] AS [c] -OUTER APPLY ( - SELECT CASE - WHEN [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] - ) THEN 1 - ELSE 0 - END AS [value] -) AS [s] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs index b4d340b0f86..2bf9c43004f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindCompiledQuerySqlServerTest.cs @@ -178,25 +178,19 @@ public override void Query_with_contains() AssertSql( """ -@args='["ALFKI"]' (Size = 4000) +@args1='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@args) WITH ([value] nchar(5) '$') AS [a] -) +WHERE [c].[CustomerID] = @args1 """, // """ -@args='["ANATR"]' (Size = 4000) +@args1='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@args) WITH ([value] nchar(5) '$') AS [a] -) +WHERE [c].[CustomerID] = @args1 """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindEFPropertyIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindEFPropertyIncludeQuerySqlServerTest.cs index ff2faffb210..1b6275c2757 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindEFPropertyIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindEFPropertyIncludeQuerySqlServerTest.cs @@ -630,25 +630,19 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -978,27 +972,14 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -1374,25 +1355,19 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -1853,27 +1828,14 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeNoTrackingQuerySqlServerTest.cs index d213b26db6c..d90befd0c2b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeNoTrackingQuerySqlServerTest.cs @@ -169,25 +169,19 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -451,25 +445,19 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -2067,27 +2055,14 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -2101,27 +2076,14 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs index 938bfc83450..b61c3060e41 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs @@ -1516,27 +1516,14 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -1550,27 +1537,14 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -1584,25 +1558,19 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -1618,25 +1586,19 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs index c4e3126bb1f..5af43749bcc 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs @@ -963,19 +963,20 @@ public override async Task Join_local_collection_int_closure_is_cached_correctly AssertSql( """ -@p='[1,2]' (Size = 4000) +@p1='1' +@p2='2' SELECT [e].[EmployeeID] FROM [Employees] AS [e] -INNER JOIN OPENJSON(@p) WITH ([value] int '$') AS [p] ON [e].[EmployeeID] = [p].[value] +INNER JOIN (VALUES (@p1), (@p2)) AS [p]([Value]) ON [e].[EmployeeID] = [p].[Value] """, // """ -@p='[3]' (Size = 4000) +@p1='3' SELECT [e].[EmployeeID] FROM [Employees] AS [e] -INNER JOIN OPENJSON(@p) WITH ([value] int '$') AS [p] ON [e].[EmployeeID] = [p].[value] +INNER JOIN (VALUES (@p1)) AS [p]([Value]) ON [e].[EmployeeID] = [p].[Value] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 5129e84eb5a..67eb04a3756 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -3847,25 +3847,20 @@ public override async Task Contains_with_DateTime_Date(bool async) AssertSql( """ -@dates='["1996-07-04T00:00:00","1996-07-16T00:00:00"]' (Size = 4000) +@dates1='1996-07-04T00:00:00.0000000' (DbType = DateTime) +@dates2='1996-07-16T00:00:00.0000000' (DbType = DateTime) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE CONVERT(date, [o].[OrderDate]) IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetime '$') AS [d] -) +WHERE CONVERT(date, [o].[OrderDate]) IN (@dates1, @dates2) """, // """ -@dates='["1996-07-04T00:00:00"]' (Size = 4000) +@dates1='1996-07-04T00:00:00.0000000' (DbType = DateTime) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE CONVERT(date, [o].[OrderDate]) IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetime '$') AS [d] -) +WHERE CONVERT(date, [o].[OrderDate]) = @dates1 """); } @@ -4886,17 +4881,8 @@ public override async Task OrderBy_empty_list_contains(bool async) AssertSql( """ -@list='[]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -4906,17 +4892,8 @@ public override async Task OrderBy_empty_list_does_not_contains(bool async) AssertSql( """ -@list='[]' (Size = 4000) - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -5444,9 +5421,11 @@ public override async Task Entity_equality_contains_with_list_of_null(bool async AssertSql( """ +@entity_equality_customers_CustomerID1='ALFKI' (Size = 5) (DbType = StringFixedLength) + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' +WHERE [c].[CustomerID] = @entity_equality_customers_CustomerID1 """); } @@ -6093,15 +6072,17 @@ FROM [Customers] AS [c] """, // """ -@orderIds='[10643,10692,10702,10835,10952,11011]' (Size = 4000) +@orderIds1='10643' +@orderIds2='10692' +@orderIds3='10702' +@orderIds4='10835' +@orderIds5='10952' +@orderIds6='11011' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE [o].[OrderID] IN ( - SELECT [o0].[value] - FROM OPENJSON(@orderIds) WITH ([value] int '$') AS [o0] -) +WHERE [o].[OrderID] IN (@orderIds1, @orderIds2, @orderIds3, @orderIds4, @orderIds5, @orderIds6) """); } @@ -7052,30 +7033,22 @@ public override async Task Parameter_collection_Contains_with_projection_and_ord AssertSql( """ -@ids='[10248,10249]' (Size = 4000) +@ids1='10248' +@ids2='10249' SELECT [o].[Quantity] AS [Key], ( SELECT MAX([o1].[OrderDate]) FROM [Order Details] AS [o0] INNER JOIN [Orders] AS [o1] ON [o0].[OrderID] = [o1].[OrderID] - WHERE [o0].[OrderID] IN ( - SELECT [i0].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i0] - ) AND [o].[Quantity] = [o0].[Quantity]) AS [MaxTimestamp] + WHERE [o0].[OrderID] IN (@ids1, @ids2) AND [o].[Quantity] = [o0].[Quantity]) AS [MaxTimestamp] FROM [Order Details] AS [o] -WHERE [o].[OrderID] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [o].[OrderID] IN (@ids1, @ids2) GROUP BY [o].[Quantity] ORDER BY ( SELECT MAX([o1].[OrderDate]) FROM [Order Details] AS [o0] INNER JOIN [Orders] AS [o1] ON [o0].[OrderID] = [o1].[OrderID] - WHERE [o0].[OrderID] IN ( - SELECT [i0].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i0] - ) AND [o].[Quantity] = [o0].[Quantity]) + WHERE [o0].[OrderID] IN (@ids1, @ids2) AND [o].[Quantity] = [o0].[Quantity]) """); } @@ -7085,14 +7058,12 @@ public override async Task Contains_over_concatenated_columns_with_different_siz AssertSql( """ -@data='["ALFKIAlfreds Futterkiste","ANATRAna Trujillo Emparedados y helados"]' (Size = 4000) +@data1='ALFKIAlfreds Futterkiste' (Size = 45) +@data2='ANATRAna Trujillo Emparedados y helados' (Size = 45) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] + [c].[CompanyName] IN ( - SELECT [d].[value] - FROM OPENJSON(@data) WITH ([value] nvarchar(45) '$') AS [d] -) +WHERE [c].[CustomerID] + [c].[CompanyName] IN (@data1, @data2) """); } @@ -7102,14 +7073,13 @@ public override async Task Contains_over_concatenated_column_and_constant(bool a AssertSql( """ -@data='["ALFKISomeConstant","ANATRSomeConstant","ALFKIX"]' (Size = 4000) +@data1='ALFKISomeConstant' (Size = 4000) +@data2='ANATRSomeConstant' (Size = 4000) +@data3='ALFKIX' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] + N'SomeConstant' IN ( - SELECT [d].[value] - FROM OPENJSON(@data) WITH ([value] nvarchar(max) '$') AS [d] -) +WHERE [c].[CustomerID] + N'SomeConstant' IN (@data1, @data2, @data3) """); } @@ -7119,15 +7089,15 @@ public override async Task Contains_over_concatenated_columns_both_fixed_length( AssertSql( """ -@data='["ALFKIALFKI","ALFKI","ANATRAna Trujillo Emparedados y helados","ANATRANATR"]' (Size = 4000) +@data1='ALFKIALFKI' (Size = 10) (DbType = StringFixedLength) +@data2='ALFKI' (Size = 10) +@data3='ANATRAna Trujillo Emparedados y helados' (Size = 4000) +@data4='ANATRANATR' (Size = 10) (DbType = StringFixedLength) SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] -WHERE COALESCE([o].[CustomerID], N'') + COALESCE([c].[CustomerID], N'') IN ( - SELECT [d].[value] - FROM OPENJSON(@data) WITH ([value] nchar(10) '$') AS [d] -) +WHERE COALESCE([o].[CustomerID], N'') + COALESCE([c].[CustomerID], N'') IN (@data1, @data2, @data3, @data4) """); } @@ -7138,14 +7108,13 @@ public override async Task Contains_over_concatenated_column_and_parameter(bool AssertSql( """ @someVariable='SomeVariable' (Size = 4000) -@data='["ALFKISomeVariable","ANATRSomeVariable","ALFKIX"]' (Size = 4000) +@data1='ALFKISomeVariable' (Size = 4000) +@data2='ANATRSomeVariable' (Size = 4000) +@data3='ALFKIX' (Size = 4000) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] + @someVariable IN ( - SELECT [d].[value] - FROM OPENJSON(@data) WITH ([value] nvarchar(max) '$') AS [d] -) +WHERE [c].[CustomerID] + @someVariable IN (@data1, @data2, @data3) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs index e1f57a950f9..944b04970b8 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs @@ -773,7 +773,12 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ AssertSql( """ -@orderIds='[10643,10692,10702,10835,10952,11011]' (Size = 4000) +@orderIds1='10643' +@orderIds2='10692' +@orderIds3='10702' +@orderIds4='10835' +@orderIds5='10952' +@orderIds6='11011' SELECT [s0].[CustomerID], [s0].[Address], [s0].[City], [s0].[CompanyName], [s0].[ContactName], [s0].[ContactTitle], [s0].[Country], [s0].[Fax], [s0].[Phone], [s0].[PostalCode], [s0].[Region] FROM [Customers] AS [c] @@ -783,10 +788,7 @@ LEFT JOIN ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[CustomerID] AS [CustomerID0], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID], [c0].[CustomerID]) AS [row] FROM [Orders] AS [o] LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] - WHERE [o].[OrderID] IN ( - SELECT [o0].[value] - FROM OPENJSON(@orderIds) WITH ([value] int '$') AS [o0] - ) + WHERE [o].[OrderID] IN (@orderIds1, @orderIds2, @orderIds3, @orderIds4, @orderIds5, @orderIds6) ) AS [s] WHERE [s].[row] <= 1 ) AS [s0] ON [c].[CustomerID] = [s0].[CustomerID0] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index 482b951a52f..fe58a38c688 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -2180,7 +2180,9 @@ public override async Task Projecting_after_navigation_and_distinct(bool async) AssertSql( """ -@filteredOrderIds='[10248,10249,10250]' (Size = 4000) +@filteredOrderIds1='10248' +@filteredOrderIds2='10249' +@filteredOrderIds3='10250' SELECT [s].[CustomerID], [o1].[CustomerID], [o1].[OrderID], [o1].[OrderDate] FROM ( @@ -2191,10 +2193,7 @@ FROM [Orders] AS [o] OUTER APPLY ( SELECT [s].[CustomerID], [o0].[OrderID], [o0].[OrderDate] FROM [Orders] AS [o0] - WHERE [s].[CustomerID] IS NOT NULL AND [s].[CustomerID] = [o0].[CustomerID] AND [o0].[OrderID] IN ( - SELECT [f].[value] - FROM OPENJSON(@filteredOrderIds) WITH ([value] int '$') AS [f] - ) + WHERE [s].[CustomerID] IS NOT NULL AND [s].[CustomerID] = [o0].[CustomerID] AND [o0].[OrderID] IN (@filteredOrderIds1, @filteredOrderIds2, @filteredOrderIds3) ) AS [o1] ORDER BY [s].[CustomerID], [o1].[OrderID] """); @@ -2206,7 +2205,9 @@ public override async Task Correlated_collection_after_distinct_with_complex_pro AssertSql( """ -@filteredOrderIds='[10248,10249,10250]' (Size = 4000) +@filteredOrderIds1='10248' +@filteredOrderIds2='10249' +@filteredOrderIds3='10250' SELECT [o0].[OrderID], [o0].[Complex], [o2].[Outer], [o2].[Inner], [o2].[OrderDate] FROM ( @@ -2216,10 +2217,7 @@ FROM [Orders] AS [o] OUTER APPLY ( SELECT [o0].[OrderID] AS [Outer], [o1].[OrderID] AS [Inner], [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE [o1].[OrderID] = [o0].[OrderID] AND [o1].[OrderID] IN ( - SELECT [f].[value] - FROM OPENJSON(@filteredOrderIds) WITH ([value] int '$') AS [f] - ) + WHERE [o1].[OrderID] = [o0].[OrderID] AND [o1].[OrderID] IN (@filteredOrderIds1, @filteredOrderIds2, @filteredOrderIds3) ) AS [o2] ORDER BY [o0].[OrderID] """); @@ -2231,7 +2229,9 @@ public override async Task Correlated_collection_after_distinct_not_containing_o AssertSql( """ -@filteredOrderIds='[10248,10249,10250]' (Size = 4000) +@filteredOrderIds1='10248' +@filteredOrderIds2='10249' +@filteredOrderIds3='10250' SELECT [o0].[OrderDate], [o0].[CustomerID], [o2].[Outer1], [o2].[Outer2], [o2].[Inner], [o2].[OrderDate] FROM ( @@ -2241,10 +2241,7 @@ FROM [Orders] AS [o] OUTER APPLY ( SELECT [o0].[OrderDate] AS [Outer1], [o0].[CustomerID] AS [Outer2], [o1].[OrderID] AS [Inner], [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE ([o1].[CustomerID] = [o0].[CustomerID] OR ([o1].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL)) AND [o1].[OrderID] IN ( - SELECT [f].[value] - FROM OPENJSON(@filteredOrderIds) WITH ([value] int '$') AS [f] - ) + WHERE ([o1].[CustomerID] = [o0].[CustomerID] OR ([o1].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL)) AND [o1].[OrderID] IN (@filteredOrderIds1, @filteredOrderIds2, @filteredOrderIds3) ) AS [o2] ORDER BY [o0].[OrderDate], [o0].[CustomerID] """); @@ -2268,7 +2265,9 @@ public override async Task Correlated_collection_after_groupby_with_complex_proj AssertSql( """ -@filteredOrderIds='[10248,10249,10250]' (Size = 4000) +@filteredOrderIds1='10248' +@filteredOrderIds2='10249' +@filteredOrderIds3='10250' SELECT [o2].[OrderID], [o2].[Complex], [o3].[Outer], [o3].[Inner], [o3].[OrderDate] FROM ( @@ -2282,10 +2281,7 @@ FROM [Orders] AS [o] OUTER APPLY ( SELECT [o2].[OrderID] AS [Outer], [o1].[OrderID] AS [Inner], [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE [o1].[OrderID] = [o2].[OrderID] AND [o1].[OrderID] IN ( - SELECT [f].[value] - FROM OPENJSON(@filteredOrderIds) WITH ([value] int '$') AS [f] - ) + WHERE [o1].[OrderID] = [o2].[OrderID] AND [o1].[OrderID] IN (@filteredOrderIds1, @filteredOrderIds2, @filteredOrderIds3) ) AS [o3] ORDER BY [o2].[OrderID] """); @@ -2708,7 +2704,9 @@ public override async Task Correlated_collection_after_groupby_with_complex_proj AssertSql( """ -@filteredOrderIds='[10248,10249,10250]' (Size = 4000) +@filteredOrderIds1='10248' +@filteredOrderIds2='10249' +@filteredOrderIds3='10250' SELECT [o2].[CustomerID], [o2].[Complex], [o3].[Outer], [o3].[Inner], [o3].[OrderDate] FROM ( @@ -2722,10 +2720,7 @@ FROM [Orders] AS [o] OUTER APPLY ( SELECT [o2].[CustomerID] AS [Outer], [o1].[OrderID] AS [Inner], [o1].[OrderDate] FROM [Orders] AS [o1] - WHERE ([o1].[CustomerID] = [o2].[CustomerID] OR ([o1].[CustomerID] IS NULL AND [o2].[CustomerID] IS NULL)) AND [o1].[OrderID] IN ( - SELECT [f].[value] - FROM OPENJSON(@filteredOrderIds) WITH ([value] int '$') AS [f] - ) + WHERE ([o1].[CustomerID] = [o2].[CustomerID] OR ([o1].[CustomerID] IS NULL AND [o2].[CustomerID] IS NULL)) AND [o1].[OrderID] IN (@filteredOrderIds1, @filteredOrderIds2, @filteredOrderIds3) ) AS [o3] ORDER BY [o2].[CustomerID], [o2].[Complex] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQuerySqlServerTest.cs index 306ad8b0133..6453d868381 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQuerySqlServerTest.cs @@ -159,42 +159,33 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='["ALFKI"]' (Size = 4000) +@list2='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS @@ -1157,42 +1148,33 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='["ALFKI"]' (Size = 4000) +@list2='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS @@ -1605,44 +1587,24 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END, [c].[CustomerID] +ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='[]' (Size = 4000) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( - SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END, [c].[CustomerID] + ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS ) AS [c0] INNER JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -1785,44 +1747,24 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END, [c].[CustomerID] +ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='[]' (Size = 4000) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( - SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END, [c].[CustomerID] + ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS ) AS [c0] INNER JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs index 4f4a591a867..3a8541b00fc 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs @@ -2125,44 +2125,24 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END, [c].[CustomerID] +ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='[]' (Size = 4000) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( - SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END, [c].[CustomerID] + ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS ) AS [c0] INNER JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -2176,44 +2156,24 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END, [c].[CustomerID] +ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='[]' (Size = 4000) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( - SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END, [c].[CustomerID] + ORDER BY (SELECT 1), [c].[CustomerID] OFFSET @p ROWS ) AS [c0] INNER JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -2227,42 +2187,33 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='["ALFKI"]' (Size = 4000) +@list2='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS @@ -2278,42 +2229,33 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS """, // """ -@list='["ALFKI"]' (Size = 4000) +@list2='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c0].[CustomerID] FROM ( SELECT [c].[CustomerID], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list2 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END, [c].[CustomerID] OFFSET @p ROWS diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindStringIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindStringIncludeQuerySqlServerTest.cs index 3ca97ba898e..c6d7a2e914d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindStringIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindStringIncludeQuerySqlServerTest.cs @@ -630,25 +630,19 @@ public override async Task Include_collection_OrderBy_list_does_not_contains(boo AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] <> @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -978,27 +972,14 @@ public override async Task Include_collection_OrderBy_empty_list_contains(bool a AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(0 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] @@ -1374,25 +1355,19 @@ public override async Task Include_collection_OrderBy_list_contains(bool async) AssertSql( """ -@list='["ALFKI"]' (Size = 4000) +@list1='ALFKI' (Size = 5) (DbType = StringFixedLength) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' ORDER BY CASE - WHEN [c].[CustomerID] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) + WHEN [c].[CustomerID] = @list1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END OFFSET @p ROWS @@ -1853,27 +1828,14 @@ public override async Task Include_collection_OrderBy_empty_list_does_not_contai AssertSql( """ -@list='[]' (Size = 4000) @p='1' SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c] + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], CAST(1 AS bit) AS [c] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%' - ORDER BY CASE - WHEN [c].[CustomerID] NOT IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nchar(5) '$') AS [l] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + ORDER BY (SELECT 1) OFFSET @p ROWS ) AS [c0] LEFT JOIN [Orders] AS [o] ON [c0].[CustomerID] = [o].[CustomerID] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs index 483e31e1cc7..f0f1f20ff23 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs @@ -1464,10 +1464,17 @@ ORDER BY [c0].[CustomerID] """, // """ +@entity_equality_customer_Orders_OrderID1='10643' +@entity_equality_customer_Orders_OrderID2='10692' +@entity_equality_customer_Orders_OrderID3='10702' +@entity_equality_customer_Orders_OrderID4='10835' +@entity_equality_customer_Orders_OrderID5='10952' +@entity_equality_customer_Orders_OrderID6='11011' + SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice] FROM [Order Details] AS [o] INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] -WHERE [o0].[OrderID] IN (10643, 10692, 10702, 10835, 10952, 11011) +WHERE [o0].[OrderID] IN (@entity_equality_customer_Orders_OrderID1, @entity_equality_customer_Orders_OrderID2, @entity_equality_customer_Orders_OrderID3, @entity_equality_customer_Orders_OrderID4, @entity_equality_customer_Orders_OrderID5, @entity_equality_customer_Orders_OrderID6) """); } @@ -1655,14 +1662,11 @@ public override async Task Generic_Ilist_contains_translates_to_server(bool asyn AssertSql( """ -@cities='["Seattle"]' (Size = 4000) +@cities1='Seattle' (Size = 15) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[City] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] nvarchar(15) '$') AS [c0] -) +WHERE [c].[City] = @cities1 """); } @@ -2016,14 +2020,12 @@ public override async Task Where_list_object_contains_over_value_type(bool async AssertSql( """ -@orderIds='[10248,10249]' (Size = 4000) +@orderIds1='10248' +@orderIds2='10249' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[OrderID] IN ( - SELECT [o0].[value] - FROM OPENJSON(@orderIds) WITH ([value] int '$') AS [o0] -) +WHERE [o].[OrderID] IN (@orderIds1, @orderIds2) """); } @@ -2033,14 +2035,12 @@ public override async Task Where_array_of_object_contains_over_value_type(bool a AssertSql( """ -@orderIds='[10248,10249]' (Size = 4000) +@orderIds1='10248' +@orderIds2='10249' SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[OrderID] IN ( - SELECT [o0].[value] - FROM OPENJSON(@orderIds) WITH ([value] int '$') AS [o0] -) +WHERE [o].[OrderID] IN (@orderIds1, @orderIds2) """); } @@ -2120,7 +2120,6 @@ public override async Task Multiple_AndAlso_on_same_column_converted_to_in_using { await base.Multiple_AndAlso_on_same_column_converted_to_in_using_parameters(async); - // issue #21462 AssertSql( """ @prm1='ALFKI' (Size = 5) (DbType = StringFixedLength) @@ -2137,7 +2136,6 @@ public override async Task Array_of_parameters_Contains_OrElse_comparison_with_c { await base.Array_of_parameters_Contains_OrElse_comparison_with_constant_gets_combined_to_one_in(async); - // issue #21462 AssertSql( """ @prm1='ALFKI' (Size = 5) (DbType = StringFixedLength) @@ -2153,7 +2151,6 @@ public override async Task Multiple_OrElse_on_same_column_with_null_parameter_co { await base.Multiple_OrElse_on_same_column_with_null_parameter_comparison_converted_to_in(async); - // issue #21462 AssertSql( """ SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] @@ -2168,14 +2165,12 @@ public override async Task Parameter_array_Contains_OrElse_comparison_with_const AssertSql( """ -@array='["ALFKI","ANATR"]' (Size = 4000) +@array1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@array2='ANATR' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@array) WITH ([value] nchar(5) '$') AS [a] -) OR [c].[CustomerID] = N'ANTON' +WHERE [c].[CustomerID] IN (@array1, @array2) OR [c].[CustomerID] = N'ANTON' """); } @@ -2186,15 +2181,13 @@ public override async Task Parameter_array_Contains_OrElse_comparison_with_param AssertSql( """ @prm1='ANTON' (Size = 5) (DbType = StringFixedLength) -@array='["ALFKI","ANATR"]' (Size = 4000) +@array1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@array2='ANATR' (Size = 5) (DbType = StringFixedLength) @prm2='ALFKI' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] = @prm1 OR [c].[CustomerID] IN ( - SELECT [a].[value] - FROM OPENJSON(@array) WITH ([value] nchar(5) '$') AS [a] -) OR [c].[CustomerID] = @prm2 +WHERE [c].[CustomerID] = @prm1 OR [c].[CustomerID] IN (@array1, @array2) OR [c].[CustomerID] = @prm2 """); } @@ -2496,14 +2489,13 @@ public override async Task Where_Contains_and_comparison(bool async) AssertSql( """ -@customerIds='["ALFKI","FISSA","WHITC"]' (Size = 4000) +@customerIds1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@customerIds2='FISSA' (Size = 5) (DbType = StringFixedLength) +@customerIds3='WHITC' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [c0].[value] - FROM OPENJSON(@customerIds) WITH ([value] nchar(5) '$') AS [c0] -) AND [c].[City] = N'Seattle' +WHERE [c].[CustomerID] IN (@customerIds1, @customerIds2, @customerIds3) AND [c].[City] = N'Seattle' """); } @@ -2513,14 +2505,12 @@ public override async Task Where_Contains_or_comparison(bool async) AssertSql( """ -@customerIds='["ALFKI","FISSA"]' (Size = 4000) +@customerIds1='ALFKI' (Size = 5) (DbType = StringFixedLength) +@customerIds2='FISSA' (Size = 5) (DbType = StringFixedLength) SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] -WHERE [c].[CustomerID] IN ( - SELECT [c0].[value] - FROM OPENJSON(@customerIds) WITH ([value] nchar(5) '$') AS [c0] -) OR [c].[City] = N'Seattle' +WHERE [c].[CustomerID] IN (@customerIds1, @customerIds2) OR [c].[City] = N'Seattle' """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index aeba22da99b..8e5143af447 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -2730,14 +2730,11 @@ public override async Task Contains_with_local_array_closure_with_null(bool asyn AssertSql( """ -@ids_without_nulls='["Foo"]' (Size = 4000) +@ids1='Foo' (Size = 4000) SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids_without_nulls) AS [i] -) OR [e].[NullableStringA] IS NULL +WHERE [e].[NullableStringA] IS NULL OR [e].[NullableStringA] = @ids1 """); } @@ -2747,14 +2744,11 @@ public override async Task Contains_with_local_array_closure_false_with_null(boo AssertSql( """ -@ids_without_nulls='["Foo"]' (Size = 4000) +@ids1='Foo' (Size = 4000) SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids_without_nulls) AS [i] -) AND [e].[NullableStringA] IS NOT NULL +WHERE [e].[NullableStringA] IS NOT NULL AND [e].[NullableStringA] <> @ids1 """); } @@ -2764,14 +2758,11 @@ public override async Task Contains_with_local_nullable_array_closure_negated(bo AssertSql( """ -@ids='["Foo"]' (Size = 4000) +@ids1='Foo' (Size = 4000) SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] nvarchar(max) '$') AS [i] -) OR [e].[NullableStringA] IS NULL +WHERE [e].[NullableStringA] <> @ids1 OR [e].[NullableStringA] IS NULL """); } @@ -2781,14 +2772,11 @@ public override async Task Contains_with_local_array_closure_with_multiple_nulls AssertSql( """ -@ids_without_nulls='["Foo"]' (Size = 4000) +@ids1='Foo' (Size = 4000) SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids_without_nulls) AS [i] -) OR [e].[NullableStringA] IS NULL +WHERE [e].[NullableStringA] IS NULL OR [e].[NullableStringA] = @ids1 """); } @@ -3089,14 +3077,12 @@ public override async Task Where_conditional_search_condition_in_result(bool asy AssertSql( """ -@list='["Foo","Bar"]' (Size = 4000) +@list1='Foo' (Size = 4000) +@list2='Bar' (Size = 4000) SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[StringA] IN ( - SELECT [l].[value] - FROM OPENJSON(@list) WITH ([value] nvarchar(max) '$') AS [l] -) +WHERE [e].[StringA] IN (@list1, @list2) """, // """ @@ -3135,14 +3121,12 @@ public override void Where_contains_on_parameter_array_with_relational_null_sema AssertSql( """ -@names='["Foo","Bar"]' (Size = 4000) +@names1='Foo' (Size = 4000) +@names2='Bar' (Size = 4000) SELECT [e].[NullableStringA] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) +WHERE [e].[NullableStringA] IN (@names1, @names2) """); } @@ -3152,14 +3136,9 @@ public override void Where_contains_on_parameter_empty_array_with_relational_nul AssertSql( """ -@names='[]' (Size = 4000) - SELECT [e].[NullableStringA] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) +WHERE 0 = 1 """); } @@ -3169,14 +3148,11 @@ public override void Where_contains_on_parameter_array_with_just_null_with_relat AssertSql( """ -@names='[null]' (Size = 4000) +@names1=NULL (Size = 4000) SELECT [e].[NullableStringA] FROM [Entities1] AS [e] -WHERE [e].[NullableStringA] IN ( - SELECT [n].[value] - FROM OPENJSON(@names) WITH ([value] nvarchar(max) '$') AS [n] -) +WHERE [e].[NullableStringA] = @names1 """); } @@ -3643,47 +3619,39 @@ public override async Task Null_semantics_contains(bool async) AssertSql( """ -@ids='[1,2]' (Size = 4000) +@ids1='1' +@ids2='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[NullableIntA] IN (@ids1, @ids2) """, // """ -@ids='[1,2]' (Size = 4000) +@ids1='1' +@ids2='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) OR [e].[NullableIntA] IS NULL +WHERE [e].[NullableIntA] NOT IN (@ids1, @ids2) OR [e].[NullableIntA] IS NULL """, // """ -@ids2_without_nulls='[1,2]' (Size = 4000) +@ids21='1' +@ids22='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2_without_nulls) AS [i] -) OR [e].[NullableIntA] IS NULL +WHERE [e].[NullableIntA] IN (@ids21, @ids22) OR [e].[NullableIntA] IS NULL """, // """ -@ids2_without_nulls='[1,2]' (Size = 4000) +@ids21='1' +@ids22='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2_without_nulls) AS [i] -) AND [e].[NullableIntA] IS NOT NULL +WHERE [e].[NullableIntA] NOT IN (@ids21, @ids22) AND [e].[NullableIntA] IS NOT NULL """, // """ @@ -3717,47 +3685,26 @@ public override async Task Null_semantics_contains_array_with_no_values(bool asy AssertSql( """ -@ids='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE 0 = 1 """, // """ -@ids='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) OR [e].[NullableIntA] IS NULL """, // """ -@ids2_without_nulls='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2_without_nulls) AS [i] -) OR [e].[NullableIntA] IS NULL +WHERE [e].[NullableIntA] IS NULL """, // """ -@ids2_without_nulls='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[NullableIntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2_without_nulls) AS [i] -) AND [e].[NullableIntA] IS NOT NULL +WHERE [e].[NullableIntA] IS NOT NULL """, // """ @@ -4117,91 +4064,61 @@ public override async Task Null_semantics_contains_non_nullable_item_with_values AssertSql( """ -@ids='[1,2,null]' (Size = 4000) +@ids1='1' +@ids2='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [e].[IntA] IN (@ids1, @ids2) """, // """ -@ids_without_nulls='[1,2]' (Size = 4000) +@ids1='1' +@ids2='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids_without_nulls) AS [i] -) +WHERE [e].[IntA] NOT IN (@ids1, @ids2) """, // """ -@ids2='[1,2]' (Size = 4000) +@ids21='1' +@ids22='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2) WITH ([value] int '$') AS [i] -) +WHERE [e].[IntA] IN (@ids21, @ids22) """, // """ -@ids2='[1,2]' (Size = 4000) +@ids21='1' +@ids22='2' SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids2) WITH ([value] int '$') AS [i] -) +WHERE [e].[IntA] NOT IN (@ids21, @ids22) """, // """ -@ids3='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids3) WITH ([value] int '$') AS [i] -) +WHERE 0 = 1 """, // """ -@ids3='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids3) WITH ([value] int '$') AS [i] -) """, // """ -@ids4='[null]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids4) WITH ([value] int '$') AS [i] -) +WHERE 0 = 1 """, // """ -@ids4_without_nulls='[]' (Size = 4000) - SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE [e].[IntA] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ids4_without_nulls) AS [i] -) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledQuerySqlServerTest.cs index b06bd80a435..328577fc1b9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledQuerySqlServerTest.cs @@ -1800,14 +1800,13 @@ public override async Task Contains_with_parameterized_collection() AssertSql( """ -@ids='[1,2,3]' (Size = 4000) +@ids1='1' +@ids2='2' +@ids3='3' SELECT [b].[Id], [b].[Name], [b].[Json] FROM [Blogs] AS [b] -WHERE [b].[Id] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] -) +WHERE [b].[Id] IN (@ids1, @ids2, @ids3) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs index 2d8990fd9dd..672449555e3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrecompiledSqlPregenerationQuerySqlServerTest.cs @@ -239,9 +239,12 @@ await Test( AssertSql( """ +@names1='foo' (Size = 4000) +@names2='bar' (Size = 4000) + SELECT [b].[Id], [b].[Name] FROM [Blogs] AS [b] -WHERE [b].[Name] IN (N'foo', N'bar') +WHERE [b].[Name] IN (@names1, @names2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs index d99ee606b20..e2677da66c7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs @@ -16,6 +16,8 @@ namespace Microsoft.EntityFrameworkCore.Query; public class PrimitiveCollectionsQueryOldSqlServerTest : PrimitiveCollectionsQueryRelationalTestBase< PrimitiveCollectionsQueryOldSqlServerTest.PrimitiveCollectionsQueryOldSqlServerFixture> { + public override int? NumberOfValuesForHugeParameterCollectionTests { get; } = 5000; + public PrimitiveCollectionsQueryOldSqlServerTest( PrimitiveCollectionsQueryOldSqlServerFixture fixture, ITestOutputHelper testOutputHelper) @@ -459,8 +461,23 @@ public override Task Inline_collection_Contains_with_EF_Parameter(bool async) public override Task Inline_collection_Count_with_column_predicate_with_EF_Parameter(bool async) => AssertCompatibilityLevelTooLow(() => base.Inline_collection_Count_with_column_predicate_with_EF_Parameter(async)); - public override Task Parameter_collection_Count(bool async) - => AssertCompatibilityLevelTooLow(() => base.Parameter_collection_Count(async)); + public override async Task Parameter_collection_Count(bool async) + { + await base.Parameter_collection_Count(async); + + AssertSql( + """ +@ids1='2' +@ids2='999' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM (VALUES (@ids1), (@ids2)) AS [i]([Value]) + WHERE [i].[Value] > [p].[Id]) = 1 +"""); + } public override async Task Parameter_collection_of_ints_Contains_int(bool async) { @@ -468,15 +485,21 @@ public override async Task Parameter_collection_of_ints_Contains_int(bool async) AssertSql( """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN (10, 999) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -486,15 +509,21 @@ public override async Task Parameter_collection_HashSet_of_ints_Contains_int(boo AssertSql( """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN (10, 999) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -504,15 +533,21 @@ public override async Task Parameter_collection_ImmutableArray_of_ints_Contains_ AssertSql( """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN (10, 999) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -522,15 +557,21 @@ public override async Task Parameter_collection_of_ints_Contains_nullable_int(bo AssertSql( """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN (10, 999) +WHERE [p].[NullableInt] IN (@ints1, @ints2) """, // """ +@ints1='10' +@ints2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] NOT IN (10, 999) OR [p].[NullableInt] IS NULL +WHERE [p].[NullableInt] NOT IN (@ints1, @ints2) OR [p].[NullableInt] IS NULL """); } @@ -540,15 +581,21 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bo AssertSql( """ +@nullableInts1='10' +@nullableInts2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN (10, 999) +WHERE [p].[Int] IN (@nullableInts1, @nullableInts2) """, // """ +@nullableInts1='10' +@nullableInts2='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN (10, 999) +WHERE [p].[Int] NOT IN (@nullableInts1, @nullableInts2) """); } @@ -558,15 +605,19 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_nullab AssertSql( """ +@nullableInts1='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = 999 +WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = @nullableInts1 """, // """ +@nullableInts1='999' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IS NOT NULL AND [p].[NullableInt] <> 999 +WHERE [p].[NullableInt] IS NOT NULL AND [p].[NullableInt] <> @nullableInts1 """); } @@ -576,15 +627,21 @@ public override async Task Parameter_collection_of_strings_Contains_string(bool AssertSql( """ +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN (N'10', N'999') +WHERE [p].[String] IN (@strings1, @strings2) """, // """ +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] NOT IN (N'10', N'999') +WHERE [p].[String] NOT IN (@strings1, @strings2) """); } @@ -594,15 +651,21 @@ public override async Task Parameter_collection_of_strings_Contains_nullable_str AssertSql( """ +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IN (N'10', N'999') +WHERE [p].[NullableString] IN (@strings1, @strings2) """, // """ +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] NOT IN (N'10', N'999') OR [p].[NullableString] IS NULL +WHERE [p].[NullableString] NOT IN (@strings1, @strings2) OR [p].[NullableString] IS NULL """); } @@ -612,15 +675,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_str AssertSql( """ +@strings1='10' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] = N'10' +WHERE [p].[String] = @strings1 """, // """ +@strings1='10' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] <> N'10' +WHERE [p].[String] <> @strings1 """); } @@ -630,15 +697,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_nul AssertSql( """ +@strings1='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = N'999' +WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = @strings1 """, // """ +@strings1='999' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IS NOT NULL AND [p].[NullableString] <> N'999' +WHERE [p].[NullableString] IS NOT NULL AND [p].[NullableString] <> @strings1 """); } @@ -648,9 +719,12 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async AssertSql( """ +@dateTimes1='2020-01-10T12:30:00.0000000Z' +@dateTimes2='9999-01-01T00:00:00.0000000Z' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[DateTime] IN ('2020-01-10T12:30:00.0000000Z', '9999-01-01T00:00:00.0000000Z') +WHERE [p].[DateTime] IN (@dateTimes1, @dateTimes2) """); } @@ -660,9 +734,11 @@ public override async Task Parameter_collection_of_bools_Contains(bool async) AssertSql( """ +@bools1='True' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Bool] = CAST(1 AS bit) +WHERE [p].[Bool] = @bools1 """); } @@ -672,9 +748,12 @@ public override async Task Parameter_collection_of_enums_Contains(bool async) AssertSql( """ +@enums1='0' +@enums2='3' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Enum] IN (0, 3) +WHERE [p].[Enum] IN (@enums1, @enums2) """); } @@ -732,6 +811,21 @@ SELECT COUNT(*) """); } + public override async Task Parameter_collection_Count_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_Count_with_huge_number_of_values(async); + + Assert.Contains("VALUES", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + + Assert.DoesNotContain("OPENJSON", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + Assert.DoesNotContain("OPENJSON", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); + } + public override Task Column_collection_of_ints_Contains(bool async) => AssertCompatibilityLevelTooLow(() => base.Column_collection_of_ints_Contains(async)); @@ -839,11 +933,45 @@ ORDER BY [v].[_ord] """); } - public override Task Parameter_collection_index_Column_equal_Column(bool async) - => AssertCompatibilityLevelTooLow(() => base.Parameter_collection_index_Column_equal_Column(async)); + public override async Task Parameter_collection_index_Column_equal_Column(bool async) + { + await base.Parameter_collection_index_Column_equal_Column(async); - public override Task Parameter_collection_index_Column_equal_constant(bool async) - => AssertCompatibilityLevelTooLow(() => base.Parameter_collection_index_Column_equal_constant(async)); + AssertSql( + """ +@ints1='0' +@ints2='2' +@ints3='3' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [i].[Value] + FROM (VALUES (1, @ints1), (2, @ints2), (3, @ints3)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] + OFFSET [p].[Int] ROWS FETCH NEXT 1 ROWS ONLY) = [p].[Int] +"""); + } + + public override async Task Parameter_collection_index_Column_equal_constant(bool async) + { + await base.Parameter_collection_index_Column_equal_constant(async); + + AssertSql( + """ +@ints1='1' +@ints2='2' +@ints3='3' + +SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT [i].[Value] + FROM (VALUES (1, @ints1), (2, @ints2), (3, @ints3)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] + OFFSET [p].[Int] ROWS FETCH NEXT 1 ROWS ONLY) = 1 +"""); + } public override Task Column_collection_ElementAt(bool async) => AssertCompatibilityLevelTooLow(() => base.Column_collection_ElementAt(async)); @@ -999,16 +1127,38 @@ public override void Parameter_collection_in_subquery_and_Convert_as_compiled_qu // Base implementation asserts that a different exception is thrown } - public override Task Parameter_collection_in_subquery_Count_as_compiled_query(bool async) - => AssertTranslationFailed(() => base.Parameter_collection_in_subquery_Count_as_compiled_query(async)); + public override async Task Parameter_collection_in_subquery_Count_as_compiled_query(bool async) + { + await base.Parameter_collection_in_subquery_Count_as_compiled_query(async); + + AssertSql( + """ +@ints1='10' +@ints2='111' + +SELECT COUNT(*) +FROM [PrimitiveCollectionsEntity] AS [p] +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT [i].[Value] AS [Value0] + FROM (VALUES (1, @ints1), (2, @ints2)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] + OFFSET 1 ROWS + ) AS [i0] + WHERE [i0].[Value0] > [p].[Id]) = 1 +"""); + } public override Task Column_collection_in_subquery_Union_parameter_collection(bool async) => AssertCompatibilityLevelTooLow(() => base.Column_collection_in_subquery_Union_parameter_collection(async)); - // Base implementation asserts that a different exception is thrown - public override Task Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(bool async) - => Assert.ThrowsAsync( - () => base.Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(async)); + public override async Task Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(bool async) + { + await base.Parameter_collection_in_subquery_Union_another_parameter_collection_as_compiled_query(async); + + AssertSql(); + } public override async Task Project_collection_of_ints_simple(bool async) { @@ -1156,12 +1306,19 @@ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mappi AssertSql( """ +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN (1, 2, 3) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN (N'one', N'two', N'three') +END IN (@strings1, @strings2, @strings3) """); } @@ -1171,12 +1328,19 @@ public override async Task Nested_contains_with_arrays_and_no_inferred_type_mapp AssertSql( """ +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN (1, 2, 3) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN (N'one', N'two', N'three') +END IN (@strings1, @strings2, @strings3) """); } @@ -1186,15 +1350,21 @@ public override async Task Parameter_collection_of_structs_Contains_struct(bool AssertSql( """ +@values1='22' +@values2='33' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] IN (22, 33) +WHERE [p].[WrappedId] IN (@values1, @values2) """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN (11, 44) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -1204,15 +1374,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ +@values1='22' +@values2='33' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IN (22, 33) +WHERE [p].[NullableWrappedId] IN (@values1, @values2) """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN (11, 44) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -1222,15 +1398,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ +@values1='22' +@values2='33' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IN (22, 33) +WHERE [p].[NullableWrappedIdWithNullableComparer] IN (@values1, @values2) """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN (11, 44) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -1240,15 +1422,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_str AssertSql( """ +@values1='22' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] = 22 +WHERE [p].[WrappedId] = @values1 """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN (11, 44) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -1258,15 +1445,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ +@values1='22' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IS NULL OR [p].[NullableWrappedId] = 22 +WHERE [p].[NullableWrappedId] IS NULL OR [p].[NullableWrappedId] = @values1 """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN (11, 44) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -1276,15 +1468,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ +@values1='22' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IS NULL OR [p].[NullableWrappedIdWithNullableComparer] = 22 +WHERE [p].[NullableWrappedIdWithNullableComparer] IS NULL OR [p].[NullableWrappedIdWithNullableComparer] = @values1 """, // """ +@values1='11' +@values2='44' + SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN (11, 44) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL +WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN (@values1, @values2) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs index 2596af4e190..b57e0e025c2 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs @@ -7,6 +7,8 @@ namespace Microsoft.EntityFrameworkCore.Query; public class PrimitiveCollectionsQuerySqlServer160Test : PrimitiveCollectionsQueryRelationalTestBase< PrimitiveCollectionsQuerySqlServer160Test.PrimitiveCollectionsQuerySqlServerFixture> { + public override int? NumberOfValuesForHugeParameterCollectionTests { get; } = 5000; + public PrimitiveCollectionsQuerySqlServer160Test(PrimitiveCollectionsQuerySqlServerFixture fixture, ITestOutputHelper testOutputHelper) : base(fixture) { @@ -458,14 +460,15 @@ public override async Task Parameter_collection_Count(bool async) AssertSql( """ -@ids='[2,999]' (Size = 4000) +@ids1='2' +@ids2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - WHERE [i].[value] > [p].[Id]) = 1 + FROM (VALUES (@ids1), (@ids2)) AS [i]([Value]) + WHERE [i].[Value] > [p].[Id]) = 1 """); } @@ -475,25 +478,21 @@ public override async Task Parameter_collection_of_ints_Contains_int(bool async) AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -503,25 +502,21 @@ public override async Task Parameter_collection_HashSet_of_ints_Contains_int(boo AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -531,25 +526,21 @@ public override async Task Parameter_collection_ImmutableArray_of_ints_Contains_ AssertSql( """ -@ints='[10,999]' (Nullable = false) (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Nullable = false) (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -559,25 +550,21 @@ public override async Task Parameter_collection_of_ints_Contains_nullable_int(bo AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[NullableInt] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) OR [p].[NullableInt] IS NULL +WHERE [p].[NullableInt] NOT IN (@ints1, @ints2) OR [p].[NullableInt] IS NULL """); } @@ -587,25 +574,21 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bo AssertSql( """ -@nullableInts='[10,999]' (Size = 4000) +@nullableInts1='10' +@nullableInts2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts) WITH ([value] int '$') AS [n] -) +WHERE [p].[Int] IN (@nullableInts1, @nullableInts2) """, // """ -@nullableInts='[10,999]' (Size = 4000) +@nullableInts1='10' +@nullableInts2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts) WITH ([value] int '$') AS [n] -) +WHERE [p].[Int] NOT IN (@nullableInts1, @nullableInts2) """); } @@ -615,25 +598,19 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_nullab AssertSql( """ -@nullableInts_without_nulls='[999]' (Size = 4000) +@nullableInts1='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts_without_nulls) AS [n] -) OR [p].[NullableInt] IS NULL +WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = @nullableInts1 """, // """ -@nullableInts_without_nulls='[999]' (Size = 4000) +@nullableInts1='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts_without_nulls) AS [n] -) AND [p].[NullableInt] IS NOT NULL +WHERE [p].[NullableInt] IS NOT NULL AND [p].[NullableInt] <> @nullableInts1 """); } @@ -643,25 +620,21 @@ public override async Task Parameter_collection_of_strings_Contains_string(bool AssertSql( """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] NOT IN (@strings1, @strings2) """); } @@ -671,25 +644,21 @@ public override async Task Parameter_collection_of_strings_Contains_nullable_str AssertSql( """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[NullableString] IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) OR [p].[NullableString] IS NULL +WHERE [p].[NullableString] NOT IN (@strings1, @strings2) OR [p].[NullableString] IS NULL """); } @@ -699,25 +668,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_str AssertSql( """ -@strings='["10",null]' (Size = 4000) +@strings1='10' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] = @strings1 """, // """ -@strings_without_nulls='["10"]' (Size = 4000) +@strings1='10' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) +WHERE [p].[String] <> @strings1 """); } @@ -727,25 +690,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_nul AssertSql( """ -@strings_without_nulls='["999"]' (Size = 4000) +@strings1='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) OR [p].[NullableString] IS NULL +WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = @strings1 """, // """ -@strings_without_nulls='["999"]' (Size = 4000) +@strings1='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) AND [p].[NullableString] IS NOT NULL +WHERE [p].[NullableString] IS NOT NULL AND [p].[NullableString] <> @strings1 """); } @@ -755,14 +712,12 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async AssertSql( """ -@dateTimes='["2020-01-10T12:30:00Z","9999-01-01T00:00:00Z"]' (Size = 4000) +@dateTimes1='2020-01-10T12:30:00.0000000Z' (DbType = DateTime) +@dateTimes2='9999-01-01T00:00:00.0000000Z' (DbType = DateTime) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[DateTime] IN ( - SELECT [d].[value] - FROM OPENJSON(@dateTimes) WITH ([value] datetime '$') AS [d] -) +WHERE [p].[DateTime] IN (@dateTimes1, @dateTimes2) """); } @@ -772,14 +727,11 @@ public override async Task Parameter_collection_of_bools_Contains(bool async) AssertSql( """ -@bools='[true]' (Size = 4000) +@bools1='True' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Bool] IN ( - SELECT [b].[value] - FROM OPENJSON(@bools) WITH ([value] bit '$') AS [b] -) +WHERE [p].[Bool] = @bools1 """); } @@ -789,14 +741,12 @@ public override async Task Parameter_collection_of_enums_Contains(bool async) AssertSql( """ -@enums='[0,3]' (Size = 4000) +@enums1='0' +@enums2='3' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Enum] IN ( - SELECT [e].[value] - FROM OPENJSON(@enums) WITH ([value] int '$') AS [e] -) +WHERE [p].[Enum] IN (@enums1, @enums2) """); } @@ -808,10 +758,7 @@ public override async Task Parameter_collection_null_Contains(bool async) """ SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(NULL) WITH ([value] int '$') AS [i] -) +WHERE 0 = 1 """); } @@ -857,6 +804,21 @@ SELECT COUNT(*) """); } + public override async Task Parameter_collection_Count_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_Count_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); + } + public override async Task Column_collection_of_ints_Contains(bool async) { await base.Column_collection_of_ints_Contains(async); @@ -1487,14 +1449,15 @@ public override async Task Column_collection_Join_parameter_collection(bool asyn AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] - INNER JOIN OPENJSON(@ints) WITH ([value] int '$') AS [i0] ON [i].[value] = [i0].[value]) = 2 + INNER JOIN (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ON [i].[value] = [i0].[Value]) = 2 """); } @@ -1519,7 +1482,8 @@ public override async Task Parameter_collection_Concat_column_collection(bool as AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1527,7 +1491,7 @@ FROM [PrimitiveCollectionsEntity] AS [p] SELECT COUNT(*) FROM ( SELECT 1 AS empty - FROM OPENJSON(@ints) AS [i] + FROM (VALUES (@ints1), (@ints2)) AS [i]([Value]) UNION ALL SELECT 1 AS empty FROM OPENJSON([p].[Ints]) AS [i0] @@ -1557,7 +1521,8 @@ public override async Task Column_collection_Union_parameter_collection(bool asy AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1567,8 +1532,8 @@ SELECT COUNT(*) SELECT [i].[value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] UNION - SELECT [i0].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i0] + SELECT [i0].[Value] AS [value] + FROM (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ) AS [u]) = 2 """); } @@ -1688,22 +1653,23 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [i1].[value] + SELECT [i1].[Value] FROM ( - SELECT CAST([i].[value] AS int) AS [value] - FROM OPENJSON(@ints) AS [i] - ORDER BY CAST([i].[key] AS int) + SELECT [i].[Value] + FROM (VALUES (1, @ints1), (2, @ints2)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] OFFSET 1 ROWS ) AS [i1] UNION - SELECT [i0].[value] + SELECT [i0].[value] AS [Value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i0] ) AS [u]) = 3 """); @@ -1715,17 +1681,17 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 4000) +@Skip1='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [s].[value] - FROM OPENJSON(@Skip) WITH ([value] int '$') AS [s] + SELECT [s].[Value] + FROM (VALUES (@Skip1)) AS [s]([Value]) UNION - SELECT [i].[value] + SELECT [i].[value] AS [Value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] ) AS [u]) = 3 """); @@ -1737,17 +1703,17 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 4000) +@Skip1='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [s].[value] - FROM OPENJSON(@Skip) WITH ([value] int '$') AS [s] + SELECT [s].[Value] + FROM (VALUES (@Skip1)) AS [s]([Value]) UNION - SELECT [i2].[value] + SELECT [i2].[value] AS [Value] FROM ( SELECT TOP(20) [i1].[value] FROM ( @@ -1779,19 +1745,20 @@ public override async Task Parameter_collection_in_subquery_Count_as_compiled_qu // TODO: the subquery projection contains extra columns which we should remove AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT COUNT(*) FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT CAST([i].[value] AS int) AS [value0] - FROM OPENJSON(@ints) AS [i] - ORDER BY CAST([i].[key] AS int) + SELECT [i].[Value] AS [Value0] + FROM (VALUES (1, @ints1), (2, @ints2)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] OFFSET 1 ROWS ) AS [i0] - WHERE [i0].[value0] > [p].[Id]) = 1 + WHERE [i0].[Value0] > [p].[Id]) = 1 """); } @@ -1808,7 +1775,8 @@ public override async Task Column_collection_in_subquery_Union_parameter_collect AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1823,8 +1791,8 @@ ORDER BY CAST([i].[key] AS int) OFFSET 1 ROWS ) AS [i1] UNION - SELECT [i0].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i0] + SELECT [i0].[Value] AS [value] + FROM (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ) AS [u]) = 3 """); } @@ -2063,24 +2031,21 @@ public override async Task Project_inline_collection_with_Concat(bool async) public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping(bool async) { await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(async); - AssertSql( """ -@ints='[1,2,3]' (Size = 4000) -@strings='["one","two","three"]' (Size = 4000) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] - ) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +END IN (@strings1, @strings2, @strings3) """); } @@ -2090,21 +2055,19 @@ public override async Task Nested_contains_with_arrays_and_no_inferred_type_mapp AssertSql( """ -@ints='[1,2,3]' (Size = 4000) -@strings='["one","two","three"]' (Size = 4000) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] - ) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +END IN (@strings1, @strings2, @strings3) """); } @@ -2114,25 +2077,21 @@ public override async Task Parameter_collection_of_structs_Contains_struct(bool AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -2142,25 +2101,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[NullableWrappedId] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2170,25 +2125,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[NullableWrappedIdWithNullableComparer] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2198,25 +2149,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_str AssertSql( """ -@values='[null,22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -2226,25 +2172,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values_without_nulls) AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] IS NULL OR [p].[NullableWrappedId] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2254,25 +2195,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IN ( - SELECT [v].[value] - FROM OPENJSON(@values_without_nulls) AS [v] -) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL +WHERE [p].[NullableWrappedIdWithNullableComparer] IS NULL OR [p].[NullableWrappedIdWithNullableComparer] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL +WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN (@values1, @values2) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs index 591b1e1d270..338bad1c1ff 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs @@ -9,6 +9,8 @@ namespace Microsoft.EntityFrameworkCore.Query; public class PrimitiveCollectionsQuerySqlServerJsonTypeTest : PrimitiveCollectionsQueryRelationalTestBase< PrimitiveCollectionsQuerySqlServerJsonTypeTest.PrimitiveCollectionsQuerySqlServerFixture> { + public override int? NumberOfValuesForHugeParameterCollectionTests { get; } = 5000; + public PrimitiveCollectionsQuerySqlServerJsonTypeTest( PrimitiveCollectionsQuerySqlServerFixture fixture, ITestOutputHelper testOutputHelper) @@ -95,6 +97,21 @@ SELECT COUNT(*) """); } + public override async Task Parameter_collection_Count_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_Count_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); + } + public override async Task Inline_collection_of_ints_Contains(bool async) { await base.Inline_collection_of_ints_Contains(async); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs index fe39b9fb6ca..c0164a1fe15 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs @@ -6,6 +6,8 @@ namespace Microsoft.EntityFrameworkCore.Query; public class PrimitiveCollectionsQuerySqlServerTest : PrimitiveCollectionsQueryRelationalTestBase< PrimitiveCollectionsQuerySqlServerTest.PrimitiveCollectionsQuerySqlServerFixture> { + public override int? NumberOfValuesForHugeParameterCollectionTests { get; } = 5000; + public PrimitiveCollectionsQuerySqlServerTest(PrimitiveCollectionsQuerySqlServerFixture fixture, ITestOutputHelper testOutputHelper) : base(fixture) { @@ -481,14 +483,15 @@ public override async Task Parameter_collection_Count(bool async) AssertSql( """ -@ids='[2,999]' (Size = 4000) +@ids1='2' +@ids2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - WHERE [i].[value] > [p].[Id]) = 1 + FROM (VALUES (@ids1), (@ids2)) AS [i]([Value]) + WHERE [i].[Value] > [p].[Id]) = 1 """); } @@ -498,25 +501,21 @@ public override async Task Parameter_collection_of_ints_Contains_int(bool async) AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -526,25 +525,21 @@ public override async Task Parameter_collection_HashSet_of_ints_Contains_int(boo AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -554,25 +549,21 @@ public override async Task Parameter_collection_ImmutableArray_of_ints_Contains_ AssertSql( """ -@ints='[10,999]' (Nullable = false) (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Nullable = false) (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[Int] NOT IN (@ints1, @ints2) """); } @@ -582,25 +573,21 @@ public override async Task Parameter_collection_of_ints_Contains_nullable_int(bo AssertSql( """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) +WHERE [p].[NullableInt] IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 4000) +@ints1='10' +@ints2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] NOT IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] -) OR [p].[NullableInt] IS NULL +WHERE [p].[NullableInt] NOT IN (@ints1, @ints2) OR [p].[NullableInt] IS NULL """); } @@ -610,25 +597,21 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bo AssertSql( """ -@nullableInts='[10,999]' (Size = 4000) +@nullableInts1='10' +@nullableInts2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts) WITH ([value] int '$') AS [n] -) +WHERE [p].[Int] IN (@nullableInts1, @nullableInts2) """, // """ -@nullableInts='[10,999]' (Size = 4000) +@nullableInts1='10' +@nullableInts2='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts) WITH ([value] int '$') AS [n] -) +WHERE [p].[Int] NOT IN (@nullableInts1, @nullableInts2) """); } @@ -638,25 +621,19 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_nullab AssertSql( """ -@nullableInts_without_nulls='[999]' (Size = 4000) +@nullableInts1='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts_without_nulls) AS [n] -) OR [p].[NullableInt] IS NULL +WHERE [p].[NullableInt] IS NULL OR [p].[NullableInt] = @nullableInts1 """, // """ -@nullableInts_without_nulls='[999]' (Size = 4000) +@nullableInts1='999' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableInt] NOT IN ( - SELECT [n].[value] - FROM OPENJSON(@nullableInts_without_nulls) AS [n] -) AND [p].[NullableInt] IS NOT NULL +WHERE [p].[NullableInt] IS NOT NULL AND [p].[NullableInt] <> @nullableInts1 """); } @@ -666,25 +643,21 @@ public override async Task Parameter_collection_of_strings_Contains_string(bool AssertSql( """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] NOT IN (@strings1, @strings2) """); } @@ -694,25 +667,21 @@ public override async Task Parameter_collection_of_strings_Contains_nullable_str AssertSql( """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[NullableString] IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 4000) +@strings1='10' (Size = 4000) +@strings2='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) OR [p].[NullableString] IS NULL +WHERE [p].[NullableString] NOT IN (@strings1, @strings2) OR [p].[NullableString] IS NULL """); } @@ -722,25 +691,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_str AssertSql( """ -@strings='["10",null]' (Size = 4000) +@strings1='10' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +WHERE [p].[String] = @strings1 """, // """ -@strings_without_nulls='["10"]' (Size = 4000) +@strings1='10' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[String] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) +WHERE [p].[String] <> @strings1 """); } @@ -750,25 +713,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_nul AssertSql( """ -@strings_without_nulls='["999"]' (Size = 4000) +@strings1='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) OR [p].[NullableString] IS NULL +WHERE [p].[NullableString] IS NULL OR [p].[NullableString] = @strings1 """, // """ -@strings_without_nulls='["999"]' (Size = 4000) +@strings1='999' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableString] NOT IN ( - SELECT [s].[value] - FROM OPENJSON(@strings_without_nulls) AS [s] -) AND [p].[NullableString] IS NOT NULL +WHERE [p].[NullableString] IS NOT NULL AND [p].[NullableString] <> @strings1 """); } @@ -778,14 +735,12 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async AssertSql( """ -@dateTimes='["2020-01-10T12:30:00Z","9999-01-01T00:00:00Z"]' (Size = 4000) +@dateTimes1='2020-01-10T12:30:00.0000000Z' (DbType = DateTime) +@dateTimes2='9999-01-01T00:00:00.0000000Z' (DbType = DateTime) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[DateTime] IN ( - SELECT [d].[value] - FROM OPENJSON(@dateTimes) WITH ([value] datetime '$') AS [d] -) +WHERE [p].[DateTime] IN (@dateTimes1, @dateTimes2) """); } @@ -795,14 +750,11 @@ public override async Task Parameter_collection_of_bools_Contains(bool async) AssertSql( """ -@bools='[true]' (Size = 4000) +@bools1='True' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Bool] IN ( - SELECT [b].[value] - FROM OPENJSON(@bools) WITH ([value] bit '$') AS [b] -) +WHERE [p].[Bool] = @bools1 """); } @@ -812,14 +764,12 @@ public override async Task Parameter_collection_of_enums_Contains(bool async) AssertSql( """ -@enums='[0,3]' (Size = 4000) +@enums1='0' +@enums2='3' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Enum] IN ( - SELECT [e].[value] - FROM OPENJSON(@enums) WITH ([value] int '$') AS [e] -) +WHERE [p].[Enum] IN (@enums1, @enums2) """); } @@ -831,10 +781,7 @@ public override async Task Parameter_collection_null_Contains(bool async) """ SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(NULL) WITH ([value] int '$') AS [i] -) +WHERE 0 = 1 """); } @@ -880,6 +827,21 @@ SELECT COUNT(*) """); } + public override async Task Parameter_collection_Count_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_Count_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + Assert.Contains("OPENJSON(@ints) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); + } + public override async Task Column_collection_of_ints_Contains(bool async) { await base.Column_collection_of_ints_Contains(async); @@ -1510,14 +1472,15 @@ public override async Task Column_collection_Join_parameter_collection(bool asyn AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] - INNER JOIN OPENJSON(@ints) WITH ([value] int '$') AS [i0] ON [i].[value] = [i0].[value]) = 2 + INNER JOIN (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ON [i].[value] = [i0].[Value]) = 2 """); } @@ -1542,7 +1505,8 @@ public override async Task Parameter_collection_Concat_column_collection(bool as AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1550,7 +1514,7 @@ FROM [PrimitiveCollectionsEntity] AS [p] SELECT COUNT(*) FROM ( SELECT 1 AS empty - FROM OPENJSON(@ints) AS [i] + FROM (VALUES (@ints1), (@ints2)) AS [i]([Value]) UNION ALL SELECT 1 AS empty FROM OPENJSON([p].[Ints]) AS [i0] @@ -1581,7 +1545,8 @@ public override async Task Column_collection_Union_parameter_collection(bool asy AssertSql( """ -@ints='[11,111]' (Size = 4000) +@ints1='11' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1591,8 +1556,8 @@ SELECT COUNT(*) SELECT [i].[value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] UNION - SELECT [i0].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i0] + SELECT [i0].[Value] AS [value] + FROM (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ) AS [u]) = 2 """); } @@ -1712,22 +1677,23 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [i1].[value] + SELECT [i1].[Value] FROM ( - SELECT CAST([i].[value] AS int) AS [value] - FROM OPENJSON(@ints) AS [i] - ORDER BY CAST([i].[key] AS int) + SELECT [i].[Value] + FROM (VALUES (1, @ints1), (2, @ints2)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] OFFSET 1 ROWS ) AS [i1] UNION - SELECT [i0].[value] + SELECT [i0].[value] AS [Value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i0] ) AS [u]) = 3 """); @@ -1739,17 +1705,17 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 4000) +@Skip1='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [s].[value] - FROM OPENJSON(@Skip) WITH ([value] int '$') AS [s] + SELECT [s].[Value] + FROM (VALUES (@Skip1)) AS [s]([Value]) UNION - SELECT [i].[value] + SELECT [i].[value] AS [Value] FROM OPENJSON([p].[Ints]) WITH ([value] int '$') AS [i] ) AS [u]) = 3 """); @@ -1761,17 +1727,17 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 4000) +@Skip1='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT [s].[value] - FROM OPENJSON(@Skip) WITH ([value] int '$') AS [s] + SELECT [s].[Value] + FROM (VALUES (@Skip1)) AS [s]([Value]) UNION - SELECT [i2].[value] + SELECT [i2].[value] AS [Value] FROM ( SELECT TOP(20) [i1].[value] FROM ( @@ -1803,19 +1769,20 @@ public override async Task Parameter_collection_in_subquery_Count_as_compiled_qu // TODO: the subquery projection contains extra columns which we should remove AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT COUNT(*) FROM [PrimitiveCollectionsEntity] AS [p] WHERE ( SELECT COUNT(*) FROM ( - SELECT CAST([i].[value] AS int) AS [value0] - FROM OPENJSON(@ints) AS [i] - ORDER BY CAST([i].[key] AS int) + SELECT [i].[Value] AS [Value0] + FROM (VALUES (1, @ints1), (2, @ints2)) AS [i]([_ord], [Value]) + ORDER BY [i].[_ord] OFFSET 1 ROWS ) AS [i0] - WHERE [i0].[value0] > [p].[Id]) = 1 + WHERE [i0].[Value0] > [p].[Id]) = 1 """); } @@ -1832,7 +1799,8 @@ public override async Task Column_collection_in_subquery_Union_parameter_collect AssertSql( """ -@ints='[10,111]' (Size = 4000) +@ints1='10' +@ints2='111' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] @@ -1847,8 +1815,8 @@ ORDER BY CAST([i].[key] AS int) OFFSET 1 ROWS ) AS [i1] UNION - SELECT [i0].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i0] + SELECT [i0].[Value] AS [value] + FROM (VALUES (@ints1), (@ints2)) AS [i0]([Value]) ) AS [u]) = 3 """); } @@ -2090,21 +2058,19 @@ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mappi AssertSql( """ -@ints='[1,2,3]' (Size = 4000) -@strings='["one","two","three"]' (Size = 4000) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] - ) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +END IN (@strings1, @strings2, @strings3) """); } @@ -2114,21 +2080,19 @@ public override async Task Nested_contains_with_arrays_and_no_inferred_type_mapp AssertSql( """ -@ints='[1,2,3]' (Size = 4000) -@strings='["one","two","three"]' (Size = 4000) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 4000) +@strings2='two' (Size = 4000) +@strings3='three' (Size = 4000) SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] WHERE CASE - WHEN [p].[Int] IN ( - SELECT [i].[value] - FROM OPENJSON(@ints) WITH ([value] int '$') AS [i] - ) THEN N'one' + WHEN [p].[Int] IN (@ints1, @ints2, @ints3) THEN N'one' ELSE N'two' -END IN ( - SELECT [s].[value] - FROM OPENJSON(@strings) WITH ([value] nvarchar(max) '$') AS [s] -) +END IN (@strings1, @strings2, @strings3) """); } @@ -2138,25 +2102,21 @@ public override async Task Parameter_collection_of_structs_Contains_struct(bool AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -2166,25 +2126,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[NullableWrappedId] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2194,25 +2150,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 4000) +@values1='22' +@values2='33' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[NullableWrappedIdWithNullableComparer] IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2222,25 +2174,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_str AssertSql( """ -@values='[null,22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[WrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) +WHERE [p].[WrappedId] NOT IN (@values1, @values2) """); } @@ -2250,25 +2197,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] IN ( - SELECT [v].[value] - FROM OPENJSON(@values_without_nulls) AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] IS NULL OR [p].[NullableWrappedId] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedId] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedId] IS NULL +WHERE [p].[NullableWrappedId] NOT IN (@values1, @values2) OR [p].[NullableWrappedId] IS NULL """); } @@ -2278,25 +2220,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4000) +@values1='22' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] IN ( - SELECT [v].[value] - FROM OPENJSON(@values_without_nulls) AS [v] -) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL +WHERE [p].[NullableWrappedIdWithNullableComparer] IS NULL OR [p].[NullableWrappedIdWithNullableComparer] = @values1 """, // """ -@values='[11,44]' (Size = 4000) +@values1='11' +@values2='44' SELECT [p].[Id], [p].[Bool], [p].[Bools], [p].[DateTime], [p].[DateTimes], [p].[Enum], [p].[Enums], [p].[Int], [p].[Ints], [p].[NullableInt], [p].[NullableInts], [p].[NullableString], [p].[NullableStrings], [p].[NullableWrappedId], [p].[NullableWrappedIdWithNullableComparer], [p].[String], [p].[Strings], [p].[WrappedId] FROM [PrimitiveCollectionsEntity] AS [p] -WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] int '$') AS [v] -) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL +WHERE [p].[NullableWrappedIdWithNullableComparer] NOT IN (@values1, @values2) OR [p].[NullableWrappedIdWithNullableComparer] IS NULL """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs index 9660cdde8d7..edbf79c7720 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryFilterFuncletizationSqlServerTest.cs @@ -98,43 +98,30 @@ public override void DbContext_list_is_parameterized() """ SELECT [l].[Id], [l].[Tenant] FROM [ListFilter] AS [l] -WHERE [l].[Tenant] IN ( - SELECT [e].[value] - FROM OPENJSON(NULL) WITH ([value] int '$') AS [e] -) +WHERE 0 = 1 """, // """ -@ef_filter__TenantIds='[]' (Size = 4000) - SELECT [l].[Id], [l].[Tenant] FROM [ListFilter] AS [l] -WHERE [l].[Tenant] IN ( - SELECT [e].[value] - FROM OPENJSON(@ef_filter__TenantIds) WITH ([value] int '$') AS [e] -) +WHERE 0 = 1 """, // """ -@ef_filter__TenantIds='[1]' (Size = 4000) +@ef_filter__TenantIds1='1' SELECT [l].[Id], [l].[Tenant] FROM [ListFilter] AS [l] -WHERE [l].[Tenant] IN ( - SELECT [e].[value] - FROM OPENJSON(@ef_filter__TenantIds) WITH ([value] int '$') AS [e] -) +WHERE [l].[Tenant] = @ef_filter__TenantIds1 """, // """ -@ef_filter__TenantIds='[2,3]' (Size = 4000) +@ef_filter__TenantIds1='2' +@ef_filter__TenantIds2='3' SELECT [l].[Id], [l].[Tenant] FROM [ListFilter] AS [l] -WHERE [l].[Tenant] IN ( - SELECT [e].[value] - FROM OPENJSON(@ef_filter__TenantIds) WITH ([value] int '$') AS [e] -) +WHERE [l].[Tenant] IN (@ef_filter__TenantIds1, @ef_filter__TenantIds2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index b4c87879bfa..c5ffaa7b94b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -313,7 +313,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM ( @@ -324,10 +329,7 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] LEFT JOIN [Tags] AS [t] ON [u].[Nickname] = [t].[GearNickName] AND [u].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -342,7 +344,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM ( @@ -354,10 +361,7 @@ FROM [Officers] AS [o] ) AS [u] INNER JOIN [Cities] AS [c] ON [u].[CityOfBirthName] = [c].[Name] LEFT JOIN [Tags] AS [t] ON [u].[Nickname] = [t].[GearNickName] AND [u].[SquadId] = [t].[GearSquadId] -WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -372,7 +376,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -383,10 +392,7 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] LEFT JOIN [Tags] AS [t] ON [u].[Nickname] = [t].[GearNickName] AND [u].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -2402,14 +2408,12 @@ public override async Task Non_unicode_string_literals_in_contains_is_used_for_n AssertSql( """ -@cities='["Unknown","Jacinto\u0027s location","Ephyra\u0027s location"]' (Size = 4000) +@cities1='Unknown' (Size = 100) (DbType = AnsiString) +@cities2='Jacinto's location' (Size = 100) (DbType = AnsiString), @cities3='Ephyra's location' (Size = 100) (DbType = AnsiString) SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE [c].[Location] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] varchar(100) '$') AS [c0] -) +WHERE [c].[Location] IN (@cities1, @cities2, @cities3) """); } @@ -3430,14 +3434,13 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a AssertSql( """ -@ids='["df36f493-463f-4123-83f9-6b135deeb7ba","23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3","ab1b82d7-88db-42bd-a132-7eef9aa68af4"]' (Size = 4000) +@ids1='df36f493-463f-4123-83f9-6b135deeb7ba' +@ids2='23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3' +@ids3='ab1b82d7-88db-42bd-a132-7eef9aa68af4' SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM [Tags] AS [t] -WHERE [t].[Id] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] uniqueidentifier '$') AS [i] -) +WHERE [t].[Id] IN (@ids1, @ids2, @ids3) """); } @@ -4083,7 +4086,7 @@ public override async Task Contains_on_nullable_array_produces_correct_sql(bool AssertSql( """ -@cities_without_nulls='["Ephyra"]' (Size = 4000) +@cities1='Ephyra' (Size = 450) SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -4094,10 +4097,7 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] LEFT JOIN [Cities] AS [c] ON [u].[AssignedCityName] = [c].[Name] -WHERE [u].[SquadId] < 2 AND ([c].[Name] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities_without_nulls) AS [c0] -) OR [c].[Name] IS NULL) +WHERE [u].[SquadId] < 2 AND ([c].[Name] IS NULL OR [c].[Name] = @cities1) """); } @@ -7427,8 +7427,6 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz AssertSql( """ -@nicknames='[]' (Size = 4000) - SELECT [u].[Nickname], [u].[SquadId], [w].[Name], [w].[Id] FROM ( SELECT [g].[Nickname], [g].[SquadId], [g].[FullName] @@ -7438,13 +7436,7 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] LEFT JOIN [Weapons] AS [w] ON [u].[FullName] = [w].[OwnerFullName] -ORDER BY CASE - WHEN [u].[Nickname] IN ( - SELECT [n].[value] - FROM OPENJSON(@nicknames) WITH ([value] nvarchar(450) '$') AS [n] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END DESC, [u].[Nickname], [u].[SquadId] +ORDER BY [u].[Nickname], [u].[SquadId] """); } @@ -8274,14 +8266,11 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a """ @start='1902-01-01T10:00:00.1234567+01:30' @end='1902-01-03T10:00:00.1234567+01:30' -@dates='["1902-01-02T10:00:00.1234567+01:30"]' (Size = 4000) +@dates1='1902-01-02T10:00:00.1234567+01:30' SELECT [m].[Id], [m].[CodeName], [m].[Date], [m].[Difficulty], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline] FROM [Missions] AS [m] -WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetimeoffset '$') AS [d] -) +WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] = @dates1 """); } @@ -9150,8 +9139,6 @@ public override async Task OrderBy_Contains_empty_list(bool async) AssertSql( """ -@ids='[]' (Size = 4000) - SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[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] @@ -9160,13 +9147,6 @@ 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 [u] -ORDER BY CASE - WHEN [u].[SquadId] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -9965,15 +9945,12 @@ public override async Task Enum_array_contains(bool async) AssertSql( """ -@types_without_nulls='[1]' (Size = 4000) +@types1='1' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] LEFT JOIN [Weapons] AS [w0] ON [w].[SynergyWithId] = [w0].[Id] -WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IN ( - SELECT [t].[value] - FROM OPENJSON(@types_without_nulls) AS [t] -) OR [w0].[AmmunitionType] IS NULL) +WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IS NULL OR [w0].[AmmunitionType] = @types1) """); } @@ -10853,7 +10830,8 @@ public override async Task Where_bool_column_and_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -10863,10 +10841,7 @@ 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 [u] -WHERE [u].[HasSoulPatch] = CAST(1 AS bit) AND [u].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [u].[HasSoulPatch] = CAST(1 AS bit) AND [u].[HasSoulPatch] IN (@values1, @values2) """); } @@ -10876,7 +10851,8 @@ public override async Task Where_bool_column_or_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -10886,10 +10862,7 @@ 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 [u] -WHERE [u].[HasSoulPatch] = CAST(1 AS bit) AND [u].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [u].[HasSoulPatch] = CAST(1 AS bit) AND [u].[HasSoulPatch] IN (@values1, @values2) """); } @@ -12215,7 +12188,8 @@ public override async Task Nav_expansion_inside_Contains_argument(bool async) AssertSql( """ -@numbers='[1,-1]' (Size = 4000) +@numbers1='1' +@numbers2='-1' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -12231,10 +12205,7 @@ SELECT 1 FROM [Weapons] AS [w] WHERE [u].[FullName] = [w].[OwnerFullName]) THEN 1 ELSE 0 -END IN ( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] -) +END IN (@numbers1, @numbers2) """); } @@ -12244,7 +12215,7 @@ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_ar AssertSql( """ -@weapons='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000) +@weapons1='Marcus' Lancer' (Size = 4000), @weapons2='Dom's Gnasher' (Size = 4000) SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -12255,13 +12226,10 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] WHERE ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] AS [w0] - WHERE [u].[FullName] = [w0].[OwnerFullName] - ORDER BY [w0].[Id]) IN ( - SELECT [w].[value] - FROM OPENJSON(@weapons) WITH ([value] nvarchar(max) '$') AS [w] -) + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [u].[FullName] = [w].[OwnerFullName] + ORDER BY [w].[Id]) IN (@weapons1, @weapons2) """); } @@ -12271,7 +12239,9 @@ public override async Task Subquery_inside_Take_argument(bool async) AssertSql( """ -@numbers='[0,1,2]' (Size = 4000) +@numbers1='0' +@numbers2='1' +@numbers3='2' SELECT [u].[Nickname], [u].[SquadId], [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId] FROM ( @@ -12288,9 +12258,9 @@ LEFT JOIN ( FROM [Weapons] AS [w] ) AS [w0] WHERE [w0].[row] <= ISNULL(( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] - ORDER BY [n].[value] + SELECT [n].[Value] + FROM (VALUES (1, @numbers1), (2, @numbers2), (3, @numbers3)) AS [n]([_ord], [Value]) + ORDER BY [n].[Value] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0) ) AS [w1] ON [u].[FullName] = [w1].[OwnerFullName] ORDER BY [u].[Nickname], [u].[SquadId], [w1].[OwnerFullName], [w1].[Id] @@ -12542,9 +12512,10 @@ public override async Task Nested_contains_with_enum(bool async) AssertSql( """ -@ranks='[1]' (Size = 4000) +@ranks1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT [u].[Nickname], [u].[SquadId], [u].[AssignedCityName], [u].[CityOfBirthName], [u].[FullName], [u].[HasSoulPatch], [u].[LeaderNickname], [u].[LeaderSquadId], [u].[Rank], [u].[Discriminator] FROM ( @@ -12555,34 +12526,23 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] WHERE CASE - WHEN [u].[Rank] IN ( - SELECT [r].[value] - FROM OPENJSON(@ranks) WITH ([value] int '$') AS [r] - ) THEN @key + WHEN [u].[Rank] = @ranks1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """, // """ -@ammoTypes='[1]' (Size = 4000) +@ammoTypes1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] WHERE CASE - WHEN [w].[AmmunitionType] IN ( - SELECT [a].[value] - FROM OPENJSON(@ammoTypes) WITH ([value] int '$') AS [a] - ) THEN @key + WHEN [w].[AmmunitionType] = @ammoTypes1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index d46673bd593..f245453c24b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -297,7 +297,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' 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' @@ -305,10 +310,7 @@ WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -323,7 +325,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' 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' @@ -332,10 +339,7 @@ FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -350,7 +354,12 @@ FROM [Tags] AS [t] """, // """ -@tags='["34c8d86e-a4ac-4be5-827f-584dda348a07","df36f493-463f-4123-83f9-6b135deeb7ba","a8ad98f9-e023-4e2a-9a70-c2728455bd34","70534e05-782c-4052-8720-c2c54481ce5f","a7be028a-0cf2-448f-ab55-ce8bc5d8cf69","b39a6fba-9026-4d69-828e-fd7068673e57"]' (Size = 4000) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='df36f493-463f-4123-83f9-6b135deeb7ba' +@tags3='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags4='70534e05-782c-4052-8720-c2c54481ce5f' +@tags5='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags6='b39a6fba-9026-4d69-828e-fd7068673e57' 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' @@ -358,10 +367,7 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -2061,14 +2067,12 @@ public override async Task Non_unicode_string_literals_in_contains_is_used_for_n AssertSql( """ -@cities='["Unknown","Jacinto\u0027s location","Ephyra\u0027s location"]' (Size = 4000) +@cities1='Unknown' (Size = 100) (DbType = AnsiString) +@cities2='Jacinto's location' (Size = 100) (DbType = AnsiString), @cities3='Ephyra's location' (Size = 100) (DbType = AnsiString) SELECT [c].[Name], [c].[Location], [c].[Nation] FROM [Cities] AS [c] -WHERE [c].[Location] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] varchar(100) '$') AS [c0] -) +WHERE [c].[Location] IN (@cities1, @cities2, @cities3) """); } @@ -2936,14 +2940,13 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a AssertSql( """ -@ids='["df36f493-463f-4123-83f9-6b135deeb7ba","23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3","ab1b82d7-88db-42bd-a132-7eef9aa68af4"]' (Size = 4000) +@ids1='df36f493-463f-4123-83f9-6b135deeb7ba' +@ids2='23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3' +@ids3='ab1b82d7-88db-42bd-a132-7eef9aa68af4' SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] FROM [Tags] AS [t] -WHERE [t].[Id] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] uniqueidentifier '$') AS [i] -) +WHERE [t].[Id] IN (@ids1, @ids2, @ids3) """); } @@ -3521,7 +3524,7 @@ public override async Task Contains_on_nullable_array_produces_correct_sql(bool AssertSql( """ -@cities_without_nulls='["Ephyra"]' (Size = 4000) +@cities1='Ephyra' (Size = 450) 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' @@ -3529,10 +3532,7 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] -WHERE [g].[SquadId] < 2 AND ([c].[Name] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities_without_nulls) AS [c0] -) OR [c].[Name] IS NULL) +WHERE [g].[SquadId] < 2 AND ([c].[Name] IS NULL OR [c].[Name] = @cities1) """); } @@ -6243,18 +6243,10 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz AssertSql( """ -@nicknames='[]' (Size = 4000) - SELECT [g].[Nickname], [g].[SquadId], [w].[Name], [w].[Id] FROM [Gears] AS [g] LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] -ORDER BY CASE - WHEN [g].[Nickname] IN ( - SELECT [n].[value] - FROM OPENJSON(@nicknames) WITH ([value] nvarchar(450) '$') AS [n] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END DESC, [g].[Nickname], [g].[SquadId] +ORDER BY [g].[Nickname], [g].[SquadId] """); } @@ -6984,14 +6976,11 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a """ @start='1902-01-01T10:00:00.1234567+01:30' @end='1902-01-03T10:00:00.1234567+01:30' -@dates='["1902-01-02T10:00:00.1234567+01:30"]' (Size = 4000) +@dates1='1902-01-02T10:00:00.1234567+01:30' SELECT [m].[Id], [m].[CodeName], [m].[Date], [m].[Difficulty], [m].[Duration], [m].[Rating], [m].[Time], [m].[Timeline] FROM [Missions] AS [m] -WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetimeoffset '$') AS [d] -) +WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] = @dates1 """); } @@ -7782,20 +7771,11 @@ public override async Task OrderBy_Contains_empty_list(bool async) AssertSql( """ -@ids='[]' (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] -ORDER BY CASE - WHEN [g].[SquadId] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -8418,15 +8398,12 @@ public override async Task Enum_array_contains(bool async) AssertSql( """ -@types_without_nulls='[1]' (Size = 4000) +@types1='1' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] LEFT JOIN [Weapons] AS [w0] ON [w].[SynergyWithId] = [w0].[Id] -WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IN ( - SELECT [t].[value] - FROM OPENJSON(@types_without_nulls) AS [t] -) OR [w0].[AmmunitionType] IS NULL) +WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IS NULL OR [w0].[AmmunitionType] = @types1) """); } @@ -9171,17 +9148,15 @@ public override async Task Where_bool_column_and_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -9191,17 +9166,15 @@ public override async Task Where_bool_column_or_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -10368,7 +10341,8 @@ public override async Task Nav_expansion_inside_Contains_argument(bool async) AssertSql( """ -@numbers='[1,-1]' (Size = 4000) +@numbers1='1' +@numbers2='-1' 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' @@ -10381,10 +10355,7 @@ SELECT 1 FROM [Weapons] AS [w] WHERE [g].[FullName] = [w].[OwnerFullName]) THEN 1 ELSE 0 -END IN ( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] -) +END IN (@numbers1, @numbers2) """); } @@ -10394,7 +10365,7 @@ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_ar AssertSql( """ -@weapons='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000) +@weapons1='Marcus' Lancer' (Size = 4000), @weapons2='Dom's 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' @@ -10402,13 +10373,10 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] WHERE ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] AS [w0] - WHERE [g].[FullName] = [w0].[OwnerFullName] - ORDER BY [w0].[Id]) IN ( - SELECT [w].[value] - FROM OPENJSON(@weapons) WITH ([value] nvarchar(max) '$') AS [w] -) + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [g].[FullName] = [w].[OwnerFullName] + ORDER BY [w].[Id]) IN (@weapons1, @weapons2) """); } @@ -10418,7 +10386,9 @@ public override async Task Subquery_inside_Take_argument(bool async) AssertSql( """ -@numbers='[0,1,2]' (Size = 4000) +@numbers1='0' +@numbers2='1' +@numbers3='2' SELECT [g].[Nickname], [g].[SquadId], [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId] FROM [Gears] AS [g] @@ -10429,9 +10399,9 @@ LEFT JOIN ( FROM [Weapons] AS [w] ) AS [w0] WHERE [w0].[row] <= ISNULL(( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] - ORDER BY [n].[value] + SELECT [n].[Value] + FROM (VALUES (1, @numbers1), (2, @numbers2), (3, @numbers3)) AS [n]([_ord], [Value]) + ORDER BY [n].[Value] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0) ) AS [w1] ON [g].[FullName] = [w1].[OwnerFullName] ORDER BY [g].[Nickname], [g].[SquadId], [w1].[OwnerFullName], [w1].[Id] @@ -10655,9 +10625,10 @@ public override async Task Nested_contains_with_enum(bool async) AssertSql( """ -@ranks='[1]' (Size = 4000) +@ranks1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' 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' @@ -10665,34 +10636,23 @@ 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 [g].[Rank] IN ( - SELECT [r].[value] - FROM OPENJSON(@ranks) WITH ([value] int '$') AS [r] - ) THEN @key + WHEN [g].[Rank] = @ranks1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """, // """ -@ammoTypes='[1]' (Size = 4000) +@ammoTypes1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] WHERE CASE - WHEN [w].[AmmunitionType] IN ( - SELECT [a].[value] - FROM OPENJSON(@ammoTypes) WITH ([value] int '$') AS [a] - ) THEN @key + WHEN [w].[AmmunitionType] = @ammoTypes1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs index a3f0a818f60..ddfd414f21e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs @@ -2303,25 +2303,20 @@ public override async Task Collection_projection_over_GroupBy_over_parameter(boo AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT [l1].[Date], [l2].[Id] FROM ( SELECT [l].[Date] FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] - WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] - ) + WHERE [l].[Name] IN (@validIds1, @validIds2) GROUP BY [l].[Date] ) AS [l1] LEFT JOIN ( SELECT [l0].[Id], [l0].[Date] FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] - WHERE [l0].[Name] IN ( - SELECT [v0].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v0] - ) + WHERE [l0].[Name] IN (@validIds1, @validIds2) ) AS [l2] ON [l1].[Date] = [l2].[Date] ORDER BY [l1].[Date] """); @@ -2620,7 +2615,8 @@ public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_coll AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT CASE WHEN [l0].[Id] IS NULL THEN 0 @@ -2629,10 +2625,7 @@ ELSE [l0].[Id] FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] LEFT JOIN [LevelTwo] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] ON [l].[Id] = [l0].[Level1_Required_Id] LEFT JOIN [LevelThree] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[OneToMany_Required_Inverse3Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) ORDER BY [l].[Id], [l0].[Id] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs index a7a4200801c..f55c0b26dc0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs @@ -1844,7 +1844,8 @@ public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_coll AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT CASE WHEN [s].[OneToOne_Required_PK_Date] IS NULL OR [s].[Level1_Required_Id] IS NULL OR [s].[OneToMany_Required_Inverse2Id] IS NULL OR CASE @@ -1878,10 +1879,7 @@ WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse ) AS [l4] ON CASE WHEN [s].[OneToOne_Required_PK_Date] IS NOT NULL AND [s].[Level1_Required_Id] IS NOT NULL AND [s].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [s].[PeriodEnd0] IS NOT NULL AND [s].[PeriodStart0] IS NOT NULL THEN [s].[Id0] END = [l4].[OneToMany_Required_Inverse3Id] -WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] -) +WHERE [l].[Name] IN (@validIds1, @validIds2) ORDER BY [l].[Id], [s].[Id], [s].[Id0] """); } @@ -3032,25 +3030,20 @@ public override async Task Collection_projection_over_GroupBy_over_parameter(boo AssertSql( """ -@validIds='["L1 01","L1 02"]' (Size = 4000) +@validIds1='L1 01' (Size = 4000) +@validIds2='L1 02' (Size = 4000) SELECT [l1].[Date], [l2].[Id] FROM ( SELECT [l].[Date] FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] - WHERE [l].[Name] IN ( - SELECT [v].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v] - ) + WHERE [l].[Name] IN (@validIds1, @validIds2) GROUP BY [l].[Date] ) AS [l1] LEFT JOIN ( SELECT [l0].[Id], [l0].[Date] FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] - WHERE [l0].[Name] IN ( - SELECT [v0].[value] - FROM OPENJSON(@validIds) WITH ([value] nvarchar(max) '$') AS [v0] - ) + WHERE [l0].[Name] IN (@validIds1, @validIds2) ) AS [l2] ON [l1].[Date] = [l2].[Date] ORDER BY [l1].[Date] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 4b86beb08b0..bf8f65d8133 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -72,15 +72,10 @@ FROM [Tags] AS [t] """, // """ -@tags='[]' (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], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE 0 = 1 """); } @@ -96,16 +91,11 @@ FROM [Tags] AS [t] """, // """ -@tags='[]' (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], [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart] FROM [Gears] AS [g] INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [c].[Location] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE 0 = 1 """); } @@ -121,15 +111,10 @@ FROM [Tags] AS [t] """, // """ -@tags='[]' (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] AS [g] LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] AND [g].[SquadId] = [t].[GearSquadId] -WHERE [t].[Id] IS NOT NULL AND [t].[Id] IN ( - SELECT [t0].[value] - FROM OPENJSON(@tags) WITH ([value] uniqueidentifier '$') AS [t0] -) +WHERE 0 = 1 """); } @@ -1305,14 +1290,12 @@ public override async Task Where_bool_column_or_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -1412,15 +1395,12 @@ public override async Task Contains_on_nullable_array_produces_correct_sql(bool AssertSql( """ -@cities_without_nulls='["Ephyra"]' (Size = 4000) +@cities1='Ephyra' (Size = 450) 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] LEFT JOIN [Cities] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [c] ON [g].[AssignedCityName] = [c].[Name] -WHERE [g].[SquadId] < 2 AND ([c].[Name] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities_without_nulls) AS [c0] -) OR [c].[Name] IS NULL) +WHERE [g].[SquadId] < 2 AND ([c].[Name] IS NULL OR [c].[Name] = @cities1) """); } @@ -4964,15 +4944,12 @@ public override async Task Enum_array_contains(bool async) AssertSql( """ -@types_without_nulls='[1]' (Size = 4000) +@types1='1' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[PeriodEnd], [w].[PeriodStart], [w].[SynergyWithId] FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] LEFT JOIN [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w0] ON [w].[SynergyWithId] = [w0].[Id] -WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IN ( - SELECT [t].[value] - FROM OPENJSON(@types_without_nulls) AS [t] -) OR [w0].[AmmunitionType] IS NULL) +WHERE [w0].[Id] IS NOT NULL AND ([w0].[AmmunitionType] IS NULL OR [w0].[AmmunitionType] = @types1) """); } @@ -5487,17 +5464,8 @@ public override async Task OrderBy_Contains_empty_list(bool async) AssertSql( """ -@ids='[]' (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] -ORDER BY CASE - WHEN [g].[SquadId] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] int '$') AS [i] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END """); } @@ -5597,14 +5565,11 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a """ @start='1902-01-01T10:00:00.1234567+01:30' @end='1902-01-03T10:00:00.1234567+01:30' -@dates='["1902-01-02T10:00:00.1234567+01:30"]' (Size = 4000) +@dates1='1902-01-02T10:00:00.1234567+01:30' SELECT [m].[Id], [m].[BriefingDocument], [m].[BriefingDocumentFileExtension], [m].[CodeName], [m].[Date], [m].[Difficulty], [m].[Duration], [m].[PeriodEnd], [m].[PeriodStart], [m].[Rating], [m].[Time], [m].[Timeline] FROM [Missions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [m] -WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] IN ( - SELECT [d].[value] - FROM OPENJSON(@dates) WITH ([value] datetimeoffset '$') AS [d] -) +WHERE @start <= CAST(CONVERT(date, [m].[Timeline]) AS datetimeoffset) AND [m].[Timeline] < @end AND [m].[Timeline] = @dates1 """); } @@ -5956,14 +5921,12 @@ public override async Task Non_unicode_string_literals_in_contains_is_used_for_n AssertSql( """ -@cities='["Unknown","Jacinto\u0027s location","Ephyra\u0027s location"]' (Size = 4000) +@cities1='Unknown' (Size = 100) (DbType = AnsiString) +@cities2='Jacinto's location' (Size = 100) (DbType = AnsiString), @cities3='Ephyra's location' (Size = 100) (DbType = AnsiString) SELECT [c].[Name], [c].[Location], [c].[Nation], [c].[PeriodEnd], [c].[PeriodStart] FROM [Cities] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [c] -WHERE [c].[Location] IN ( - SELECT [c0].[value] - FROM OPENJSON(@cities) WITH ([value] varchar(100) '$') AS [c0] -) +WHERE [c].[Location] IN (@cities1, @cities2, @cities3) """); } @@ -7186,18 +7149,10 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz AssertSql( """ -@nicknames='[]' (Size = 4000) - SELECT [g].[Nickname], [g].[SquadId], [w].[Name], [w].[Id] FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] LEFT JOIN [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] ON [g].[FullName] = [w].[OwnerFullName] -ORDER BY CASE - WHEN [g].[Nickname] IN ( - SELECT [n].[value] - FROM OPENJSON(@nicknames) WITH ([value] nvarchar(450) '$') AS [n] - ) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) -END DESC, [g].[Nickname], [g].[SquadId] +ORDER BY [g].[Nickname], [g].[SquadId] """); } @@ -7476,14 +7431,13 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a AssertSql( """ -@ids='["df36f493-463f-4123-83f9-6b135deeb7ba","23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3","ab1b82d7-88db-42bd-a132-7eef9aa68af4"]' (Size = 4000) +@ids1='df36f493-463f-4123-83f9-6b135deeb7ba' +@ids2='23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3' +@ids3='ab1b82d7-88db-42bd-a132-7eef9aa68af4' SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] -WHERE [t].[Id] IN ( - SELECT [i].[value] - FROM OPENJSON(@ids) WITH ([value] uniqueidentifier '$') AS [i] -) +WHERE [t].[Id] IN (@ids1, @ids2, @ids3) """); } @@ -8088,14 +8042,12 @@ public override async Task Where_bool_column_and_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 4000) +@values1='False' +@values2='True' 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 [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN ( - SELECT [v].[value] - FROM OPENJSON(@values) WITH ([value] bit '$') AS [v] -) +WHERE [g].[HasSoulPatch] = CAST(1 AS bit) AND [g].[HasSoulPatch] IN (@values1, @values2) """); } @@ -9081,7 +9033,8 @@ public override async Task Nav_expansion_inside_Contains_argument(bool async) AssertSql( """ -@numbers='[1,-1]' (Size = 4000) +@numbers1='1' +@numbers2='-1' 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] @@ -9091,10 +9044,7 @@ 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) WITH ([value] int '$') AS [n] -) +END IN (@numbers1, @numbers2) """); } @@ -9104,18 +9054,15 @@ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_ar AssertSql( """ -@weapons='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 4000) +@weapons1='Marcus' Lancer' (Size = 4000), @weapons2='Dom's 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 ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w0] - WHERE [g].[FullName] = [w0].[OwnerFullName] - ORDER BY [w0].[Id]) IN ( - SELECT [w].[value] - FROM OPENJSON(@weapons) WITH ([value] nvarchar(max) '$') AS [w] -) + 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]) IN (@weapons1, @weapons2) """); } @@ -9125,7 +9072,9 @@ public override async Task Subquery_inside_Take_argument(bool async) AssertSql( """ -@numbers='[0,1,2]' (Size = 4000) +@numbers1='0' +@numbers2='1' +@numbers3='2' SELECT [g].[Nickname], [g].[SquadId], [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[PeriodEnd], [w1].[PeriodStart], [w1].[SynergyWithId] FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] @@ -9136,9 +9085,9 @@ LEFT JOIN ( FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] ) AS [w0] WHERE [w0].[row] <= ISNULL(( - SELECT [n].[value] - FROM OPENJSON(@numbers) WITH ([value] int '$') AS [n] - ORDER BY [n].[value] + SELECT [n].[Value] + FROM (VALUES (1, @numbers1), (2, @numbers2), (3, @numbers3)) AS [n]([_ord], [Value]) + ORDER BY [n].[Value] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY), 0) ) AS [w1] ON [g].[FullName] = [w1].[OwnerFullName] ORDER BY [g].[Nickname], [g].[SquadId], [w1].[OwnerFullName], [w1].[Id] @@ -9301,41 +9250,31 @@ public override async Task Nested_contains_with_enum(bool async) AssertSql( """ -@ranks='[1]' (Size = 4000) +@ranks1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' 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 [g].[Rank] IN ( - SELECT [r].[value] - FROM OPENJSON(@ranks) WITH ([value] int '$') AS [r] - ) THEN @key + WHEN [g].[Rank] = @ranks1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """, // """ -@ammoTypes='[1]' (Size = 4000) +@ammoTypes1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0a47bcb7-a1cb-4345-8944-c58f82d6aac7","5f221fb9-66f4-442a-92c9-d97ed5989cc7"]' (Size = 4000) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[PeriodEnd], [w].[PeriodStart], [w].[SynergyWithId] FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] WHERE CASE - WHEN [w].[AmmunitionType] IN ( - SELECT [a].[value] - FROM OPENJSON(@ammoTypes) WITH ([value] int '$') AS [a] - ) THEN @key + WHEN [w].[AmmunitionType] = @ammoTypes1 THEN @key ELSE @key -END IN ( - SELECT [k].[value] - FROM OPENJSON(@keys) WITH ([value] uniqueidentifier '$') AS [k] -) +END IN (@keys1, @keys2) """); } diff --git a/test/EFCore.SqlServer.HierarchyId.Tests/QueryTests.cs b/test/EFCore.SqlServer.HierarchyId.Tests/QueryTests.cs index 04a5f789787..34a97127b70 100644 --- a/test/EFCore.SqlServer.HierarchyId.Tests/QueryTests.cs +++ b/test/EFCore.SqlServer.HierarchyId.Tests/QueryTests.cs @@ -366,14 +366,12 @@ where ids.Contains(p.Id) Assert.Equal( """ -@ids='?' (Size = 4000) +@ids1='?' (DbType = Object) +@ids2='?' (DbType = Object) SELECT TOP(2) [p].[Name] FROM [Patriarchy] AS [p] -WHERE [p].[Id] IN ( - SELECT CAST([i].[value] AS hierarchyid) AS [value] - FROM OPENJSON(@ids) AS [i] -) +WHERE [p].[Id] IN (@ids1, @ids2) """, _db.Sql, ignoreLineEndingDifferences: true); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/AdHocMiscellaneousQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocMiscellaneousQuerySqliteTest.cs index 9bc746ce897..e878daf1ff8 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/AdHocMiscellaneousQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocMiscellaneousQuerySqliteTest.cs @@ -10,9 +10,9 @@ public class AdHocMiscellaneousQuerySqliteTest(NonSharedFixture fixture) : AdHoc protected override ITestStoreFactory TestStoreFactory => SqliteTestStoreFactory.Instance; - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) { - new SqliteDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); + new SqliteDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); return optionsBuilder; } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index 0af7969f17f..d6c8b9ee444 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -401,16 +401,18 @@ public override async Task Include_where_list_contains_navigation2(bool async) """, // """ -@tags='["34C8D86E-A4AC-4BE5-827F-584DDA348A07","70534E05-782C-4052-8720-C2C54481CE5F","A7BE028A-0CF2-448F-AB55-CE8BC5D8CF69","A8AD98F9-E023-4E2A-9A70-C2728455BD34","B39A6FBA-9026-4D69-828E-FD7068673E57","DF36F493-463F-4123-83F9-6B135DEEB7BA"]' (Size = 235) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='70534e05-782c-4052-8720-c2c54481ce5f' +@tags3='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags4='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags5='b39a6fba-9026-4d69-828e-fd7068673e57' +@tags6='df36f493-463f-4123-83f9-6b135deeb7ba' SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank", "t"."Id", "t"."GearNickName", "t"."GearSquadId", "t"."IssueDate", "t"."Note" FROM "Gears" AS "g" INNER JOIN "Cities" AS "c" ON "g"."CityOfBirthName" = "c"."Name" LEFT JOIN "Tags" AS "t" ON "g"."Nickname" = "t"."GearNickName" AND "g"."SquadId" = "t"."GearSquadId" -WHERE "c"."Location" IS NOT NULL AND "t"."Id" IN ( - SELECT "t0"."value" - FROM json_each(@tags) AS "t0" -) +WHERE "c"."Location" IS NOT NULL AND "t"."Id" IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -756,14 +758,12 @@ public override async Task Non_unicode_string_literals_in_contains_is_used_for_n AssertSql( """ -@cities='["Unknown","Jacinto\u0027s location","Ephyra\u0027s location"]' (Size = 62) +@cities1='Unknown' (Size = 7) +@cities2='Jacinto's location' (Size = 18), @cities3='Ephyra's location' (Size = 17) SELECT "c"."Name", "c"."Location", "c"."Nation" FROM "Cities" AS "c" -WHERE "c"."Location" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" -) +WHERE "c"."Location" IN (@cities1, @cities2, @cities3) """); } @@ -1424,15 +1424,10 @@ public override async Task Correlated_collection_with_complex_order_by_funcletiz AssertSql( """ -@nicknames='[]' (Size = 2) - SELECT "g"."Nickname", "g"."SquadId", "w"."Name", "w"."Id" FROM "Gears" AS "g" LEFT JOIN "Weapons" AS "w" ON "g"."FullName" = "w"."OwnerFullName" -ORDER BY "g"."Nickname" IN ( - SELECT "n"."value" - FROM json_each(@nicknames) AS "n" -) DESC, "g"."Nickname", "g"."SquadId" +ORDER BY "g"."Nickname", "g"."SquadId" """); } @@ -1665,14 +1660,12 @@ public override async Task Where_bool_column_and_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 12) +@values1='False' +@values2='True' 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 "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN (@values1, @values2) """); } @@ -2196,15 +2189,12 @@ public override async Task Contains_on_nullable_array_produces_correct_sql(bool AssertSql( """ -@cities_without_nulls='["Ephyra"]' (Size = 10) +@cities1='Ephyra' (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" LEFT JOIN "Cities" AS "c" ON "g"."AssignedCityName" = "c"."Name" -WHERE "g"."SquadId" < 2 AND ("c"."Name" IN ( - SELECT "c0"."value" - FROM json_each(@cities_without_nulls) AS "c0" -) OR "c"."Name" IS NULL) +WHERE "g"."SquadId" < 2 AND ("c"."Name" IS NULL OR "c"."Name" = @cities1) """); } @@ -2456,15 +2446,12 @@ public override async Task Enum_array_contains(bool async) AssertSql( """ -@types_without_nulls='[1]' (Size = 3) +@types1='1' SELECT "w"."Id", "w"."AmmunitionType", "w"."IsAutomatic", "w"."Name", "w"."OwnerFullName", "w"."SynergyWithId" FROM "Weapons" AS "w" LEFT JOIN "Weapons" AS "w0" ON "w"."SynergyWithId" = "w0"."Id" -WHERE "w0"."Id" IS NOT NULL AND ("w0"."AmmunitionType" IN ( - SELECT "t"."value" - FROM json_each(@types_without_nulls) AS "t" -) OR "w0"."AmmunitionType" IS NULL) +WHERE "w0"."Id" IS NOT NULL AND ("w0"."AmmunitionType" IS NULL OR "w0"."AmmunitionType" = @types1) """); } @@ -3132,15 +3119,17 @@ public override async Task Navigation_accessed_twice_outside_and_inside_subquery """, // """ -@tags='["34C8D86E-A4AC-4BE5-827F-584DDA348A07","70534E05-782C-4052-8720-C2C54481CE5F","A7BE028A-0CF2-448F-AB55-CE8BC5D8CF69","A8AD98F9-E023-4E2A-9A70-C2728455BD34","B39A6FBA-9026-4D69-828E-FD7068673E57","DF36F493-463F-4123-83F9-6B135DEEB7BA"]' (Size = 235) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='70534e05-782c-4052-8720-c2c54481ce5f' +@tags3='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags4='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags5='b39a6fba-9026-4d69-828e-fd7068673e57' +@tags6='df36f493-463f-4123-83f9-6b135deeb7ba' 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" LEFT JOIN "Tags" AS "t" ON "g"."Nickname" = "t"."GearNickName" AND "g"."SquadId" = "t"."GearSquadId" -WHERE "t"."Id" IS NOT NULL AND "t"."Id" IN ( - SELECT "t0"."value" - FROM json_each(@tags) AS "t0" -) +WHERE "t"."Id" IS NOT NULL AND "t"."Id" IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -3875,14 +3864,12 @@ public override async Task Where_bool_column_or_Contains(bool async) AssertSql( """ -@values='[false,true]' (Size = 12) +@values1='False' +@values2='True' 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 "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "g"."HasSoulPatch" AND "g"."HasSoulPatch" IN (@values1, @values2) """); } @@ -4205,15 +4192,17 @@ public override async Task Include_where_list_contains_navigation(bool async) """, // """ -@tags='["34C8D86E-A4AC-4BE5-827F-584DDA348A07","70534E05-782C-4052-8720-C2C54481CE5F","A7BE028A-0CF2-448F-AB55-CE8BC5D8CF69","A8AD98F9-E023-4E2A-9A70-C2728455BD34","B39A6FBA-9026-4D69-828E-FD7068673E57","DF36F493-463F-4123-83F9-6B135DEEB7BA"]' (Size = 235) +@tags1='34c8d86e-a4ac-4be5-827f-584dda348a07' +@tags2='70534e05-782c-4052-8720-c2c54481ce5f' +@tags3='a7be028a-0cf2-448f-ab55-ce8bc5d8cf69' +@tags4='a8ad98f9-e023-4e2a-9a70-c2728455bd34' +@tags5='b39a6fba-9026-4d69-828e-fd7068673e57' +@tags6='df36f493-463f-4123-83f9-6b135deeb7ba' SELECT "g"."Nickname", "g"."SquadId", "g"."AssignedCityName", "g"."CityOfBirthName", "g"."Discriminator", "g"."FullName", "g"."HasSoulPatch", "g"."LeaderNickname", "g"."LeaderSquadId", "g"."Rank", "t"."Id", "t"."GearNickName", "t"."GearSquadId", "t"."IssueDate", "t"."Note" FROM "Gears" AS "g" LEFT JOIN "Tags" AS "t" ON "g"."Nickname" = "t"."GearNickName" AND "g"."SquadId" = "t"."GearSquadId" -WHERE "t"."Id" IS NOT NULL AND "t"."Id" IN ( - SELECT "t0"."value" - FROM json_each(@tags) AS "t0" -) +WHERE "t"."Id" IS NOT NULL AND "t"."Id" IN (@tags1, @tags2, @tags3, @tags4, @tags5, @tags6) """); } @@ -4847,14 +4836,8 @@ public override async Task OrderBy_Contains_empty_list(bool async) AssertSql( """ -@ids='[]' (Size = 2) - 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" -ORDER BY "g"."SquadId" IN ( - SELECT "i"."value" - FROM json_each(@ids) AS "i" -) """); } @@ -7134,14 +7117,13 @@ public override async Task Contains_with_local_nullable_guid_list_closure(bool a AssertSql( """ -@ids='["DF36F493-463F-4123-83F9-6B135DEEB7BA","23CBCF9B-CE14-45CF-AAFA-2C2667EBFDD3","AB1B82D7-88DB-42BD-A132-7EEF9AA68AF4"]' (Size = 118) +@ids1='df36f493-463f-4123-83f9-6b135deeb7ba' +@ids2='23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3' +@ids3='ab1b82d7-88db-42bd-a132-7eef9aa68af4' SELECT "t"."Id", "t"."GearNickName", "t"."GearSquadId", "t"."IssueDate", "t"."Note" FROM "Tags" AS "t" -WHERE "t"."Id" IN ( - SELECT "i"."value" - FROM json_each(@ids) AS "i" -) +WHERE "t"."Id" IN (@ids1, @ids2, @ids3) """); } @@ -8703,7 +8685,8 @@ public override async Task Nav_expansion_inside_Contains_argument(bool async) AssertSql( """ -@numbers='[1,-1]' (Size = 6) +@numbers1='1' +@numbers2='-1' 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" @@ -8713,10 +8696,7 @@ SELECT 1 FROM "Weapons" AS "w" WHERE "g"."FullName" = "w"."OwnerFullName") THEN 1 ELSE 0 -END IN ( - SELECT "n"."value" - FROM json_each(@numbers) AS "n" -) +END IN (@numbers1, @numbers2) """); } @@ -8726,19 +8706,16 @@ public override async Task Nav_expansion_with_member_pushdown_inside_Contains_ar AssertSql( """ -@weapons='["Marcus\u0027 Lancer","Dom\u0027s Gnasher"]' (Size = 44) +@weapons1='Marcus' Lancer' (Size = 14), @weapons2='Dom's Gnasher' (Size = 13) 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 ( - SELECT "w0"."Name" - FROM "Weapons" AS "w0" - WHERE "g"."FullName" = "w0"."OwnerFullName" - ORDER BY "w0"."Id" - LIMIT 1) IN ( - SELECT "w"."value" - FROM json_each(@weapons) AS "w" -) + SELECT "w"."Name" + FROM "Weapons" AS "w" + WHERE "g"."FullName" = "w"."OwnerFullName" + ORDER BY "w"."Id" + LIMIT 1) IN (@weapons1, @weapons2) """); } @@ -8748,7 +8725,9 @@ public override async Task Subquery_inside_Take_argument(bool async) AssertSql( """ -@numbers='[0,1,2]' (Size = 7) +@numbers1='0' +@numbers2='1' +@numbers3='2' SELECT "g"."Nickname", "g"."SquadId", "w1"."Id", "w1"."AmmunitionType", "w1"."IsAutomatic", "w1"."Name", "w1"."OwnerFullName", "w1"."SynergyWithId" FROM "Gears" AS "g" @@ -8759,9 +8738,9 @@ LEFT JOIN ( FROM "Weapons" AS "w" ) AS "w0" WHERE "w0"."row" <= COALESCE(( - SELECT "n"."value" - FROM json_each(@numbers) AS "n" - ORDER BY "n"."value" + SELECT "n"."Value" + FROM (SELECT 1 AS "_ord", @numbers1 AS "Value" UNION ALL VALUES (2, @numbers2), (3, @numbers3)) AS "n" + ORDER BY "n"."Value" LIMIT 1 OFFSET 1), 0) ) AS "w1" ON "g"."FullName" = "w1"."OwnerFullName" ORDER BY "g"."Nickname", "g"."SquadId", "w1"."OwnerFullName", "w1"."Id" @@ -8912,41 +8891,31 @@ public override async Task Nested_contains_with_enum(bool async) AssertSql( """ -@ranks='[1]' (Size = 3) +@ranks1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0A47BCB7-A1CB-4345-8944-C58F82D6AAC7","5F221FB9-66F4-442A-92C9-D97ED5989CC7"]' (Size = 79) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' 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 "g"."Rank" IN ( - SELECT "r"."value" - FROM json_each(@ranks) AS "r" - ) THEN @key + WHEN "g"."Rank" = @ranks1 THEN @key ELSE @key -END IN ( - SELECT "k"."value" - FROM json_each(@keys) AS "k" -) +END IN (@keys1, @keys2) """, // """ -@ammoTypes='[1]' (Size = 3) +@ammoTypes1='1' @key='5f221fb9-66f4-442a-92c9-d97ed5989cc7' -@keys='["0A47BCB7-A1CB-4345-8944-C58F82D6AAC7","5F221FB9-66F4-442A-92C9-D97ED5989CC7"]' (Size = 79) +@keys1='0a47bcb7-a1cb-4345-8944-c58f82d6aac7' +@keys2='5f221fb9-66f4-442a-92c9-d97ed5989cc7' SELECT "w"."Id", "w"."AmmunitionType", "w"."IsAutomatic", "w"."Name", "w"."OwnerFullName", "w"."SynergyWithId" FROM "Weapons" AS "w" WHERE CASE - WHEN "w"."AmmunitionType" IN ( - SELECT "a"."value" - FROM json_each(@ammoTypes) AS "a" - ) THEN @key + WHEN "w"."AmmunitionType" = @ammoTypes1 THEN @key ELSE @key -END IN ( - SELECT "k"."value" - FROM json_each(@keys) AS "k" -) +END IN (@keys1, @keys2) """); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqliteTest.cs index ebfc82e21ec..fbddf89fa4f 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqliteTest.cs @@ -7,16 +7,9 @@ namespace Microsoft.EntityFrameworkCore.Query; public class NonSharedPrimitiveCollectionsQuerySqliteTest(NonSharedFixture fixture) : NonSharedPrimitiveCollectionsQueryRelationalTestBase(fixture) { - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) { - new SqliteDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); - - return optionsBuilder; - } - - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToParameters(DbContextOptionsBuilder optionsBuilder) - { - new SqliteDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToParameters(); + new SqliteDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); return optionsBuilder; } @@ -351,9 +344,9 @@ SELECT COUNT(*) """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_constants() + public override async Task Parameter_collection_Contains_with_default_constants() { - await base.Parameter_collection_of_ints_Contains_int_with_default_constants(); + await base.Parameter_collection_Contains_with_default_constants(); AssertSql( """ @@ -380,9 +373,9 @@ FROM json_each(@ids) AS "i" """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_constants_EF_Parameter() + public override async Task Parameter_collection_Contains_with_default_constants_EF_Parameter() { - await base.Parameter_collection_of_ints_Contains_int_with_default_constants_EF_Parameter(); + await base.Parameter_collection_Contains_with_default_constants_EF_Parameter(); AssertSql( """ @@ -397,9 +390,9 @@ FROM json_each(@ints) AS "i" """); } - public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameters() + public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameter() { - await base.Parameter_collection_Count_with_column_predicate_with_default_parameters(); + await base.Parameter_collection_Count_with_column_predicate_with_default_parameter(); AssertSql( """ @@ -414,9 +407,9 @@ FROM json_each(@ids) AS "i" """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_parameters() + public override async Task Parameter_collection_Contains_with_default_parameter() { - await base.Parameter_collection_of_ints_Contains_int_with_default_parameters(); + await base.Parameter_collection_Contains_with_default_parameter(); AssertSql( """ @@ -431,9 +424,9 @@ FROM json_each(@ints) AS "i" """); } - public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameters_EF_Constant() + public override async Task Parameter_collection_Count_with_column_predicate_with_default_parameter_EF_Constant() { - await base.Parameter_collection_Count_with_column_predicate_with_default_parameters_EF_Constant(); + await base.Parameter_collection_Count_with_column_predicate_with_default_parameter_EF_Constant(); AssertSql( """ @@ -446,9 +439,9 @@ SELECT COUNT(*) """); } - public override async Task Parameter_collection_of_ints_Contains_int_with_default_parameters_EF_Constant() + public override async Task Parameter_collection_Contains_with_default_parameter_EF_Constant() { - await base.Parameter_collection_of_ints_Contains_int_with_default_parameters_EF_Constant(); + await base.Parameter_collection_Contains_with_default_parameter_EF_Constant(); AssertSql( """ @@ -458,6 +451,39 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_defaul """); } + public override async Task Parameter_collection_Count_with_column_predicate_with_default_multiple_parameters() + { + await base.Parameter_collection_Count_with_column_predicate_with_default_multiple_parameters(); + + AssertSql( + """ +@ids1='2' +@ids2='999' + +SELECT "t"."Id" +FROM "TestEntity" AS "t" +WHERE ( + SELECT COUNT(*) + FROM (SELECT @ids1 AS "Value" UNION ALL VALUES (@ids2)) AS "i" + WHERE "i"."Value" > "t"."Id") = 1 +"""); + } + + public override async Task Parameter_collection_Contains_with_default_multiple_parameters() + { + await base.Parameter_collection_Contains_with_default_multiple_parameters(); + + AssertSql( + """ +@ints1='2' +@ints2='999' + +SELECT "t"."Id" +FROM "TestEntity" AS "t" +WHERE "t"."Id" IN (@ints1, @ints2) +"""); + } + protected override ITestStoreFactory TestStoreFactory => SqliteTestStoreFactory.Instance; } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqliteTest.cs index e6b3438c32c..674b7cde7ef 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqliteTest.cs @@ -129,13 +129,11 @@ public override async Task Contains_inside_aggregate_function_with_GroupBy(bool AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT COUNT(CASE - WHEN "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" - ) THEN 1 + WHEN "c"."City" IN (@cities1, @cities2) THEN 1 END) FROM "Customers" AS "c" GROUP BY "c"."Country" @@ -148,13 +146,11 @@ public override async Task Contains_inside_Average_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT AVG(CASE - WHEN "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" - ) THEN 1.0 + WHEN "c"."City" IN (@cities1, @cities2) THEN 1.0 ELSE 0.0 END) FROM "Customers" AS "c" @@ -167,13 +163,11 @@ public override async Task Contains_inside_Sum_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT COALESCE(SUM(CASE - WHEN "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" - ) THEN 1 + WHEN "c"."City" IN (@cities1, @cities2) THEN 1 ELSE 0 END), 0) FROM "Customers" AS "c" @@ -186,14 +180,12 @@ public override async Task Contains_inside_Count_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT COUNT(*) FROM "Customers" AS "c" -WHERE "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" -) +WHERE "c"."City" IN (@cities1, @cities2) """); } @@ -203,14 +195,12 @@ public override async Task Contains_inside_LongCount_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT COUNT(*) FROM "Customers" AS "c" -WHERE "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" -) +WHERE "c"."City" IN (@cities1, @cities2) """); } @@ -220,13 +210,11 @@ public override async Task Contains_inside_Max_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT MAX(CASE - WHEN "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" - ) THEN 1 + WHEN "c"."City" IN (@cities1, @cities2) THEN 1 ELSE 0 END) FROM "Customers" AS "c" @@ -239,13 +227,11 @@ public override async Task Contains_inside_Min_without_GroupBy(bool async) AssertSql( """ -@cities='["London","Berlin"]' (Size = 19) +@cities1='London' (Size = 6) +@cities2='Berlin' (Size = 6) SELECT MIN(CASE - WHEN "c"."City" IN ( - SELECT "c0"."value" - FROM json_each(@cities) AS "c0" - ) THEN 1 + WHEN "c"."City" IN (@cities1, @cities2) THEN 1 ELSE 0 END) FROM "Customers" AS "c" diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs index 4260649414b..cc161920c78 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs @@ -471,14 +471,15 @@ public override async Task Parameter_collection_Count(bool async) AssertSql( """ -@ids='[2,999]' (Size = 7) +@ids1='2' +@ids2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) - FROM json_each(@ids) AS "i" - WHERE "i"."value" > "p"."Id") = 1 + FROM (SELECT @ids1 AS "Value" UNION ALL VALUES (@ids2)) AS "i" + WHERE "i"."Value" > "p"."Id") = 1 """); } @@ -488,25 +489,21 @@ public override async Task Parameter_collection_of_ints_Contains_int(bool async) AssertSql( """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" NOT IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" NOT IN (@ints1, @ints2) """); } @@ -516,25 +513,21 @@ public override async Task Parameter_collection_HashSet_of_ints_Contains_int(boo AssertSql( """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" NOT IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" NOT IN (@ints1, @ints2) """); } @@ -544,25 +537,21 @@ public override async Task Parameter_collection_ImmutableArray_of_ints_Contains_ AssertSql( """ -@ints='[10,999]' (Nullable = false) (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Nullable = false) (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" NOT IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."Int" NOT IN (@ints1, @ints2) """); } @@ -572,25 +561,21 @@ public override async Task Parameter_collection_of_ints_Contains_nullable_int(bo AssertSql( """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableInt" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) +WHERE "p"."NullableInt" IN (@ints1, @ints2) """, // """ -@ints='[10,999]' (Size = 8) +@ints1='10' +@ints2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableInt" NOT IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" -) OR "p"."NullableInt" IS NULL +WHERE "p"."NullableInt" NOT IN (@ints1, @ints2) OR "p"."NullableInt" IS NULL """); } @@ -600,25 +585,21 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_int(bo AssertSql( """ -@nullableInts='[10,999]' (Size = 8) +@nullableInts1='10' +@nullableInts2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" IN ( - SELECT "n"."value" - FROM json_each(@nullableInts) AS "n" -) +WHERE "p"."Int" IN (@nullableInts1, @nullableInts2) """, // """ -@nullableInts='[10,999]' (Size = 8) +@nullableInts1='10' +@nullableInts2='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" NOT IN ( - SELECT "n"."value" - FROM json_each(@nullableInts) AS "n" -) +WHERE "p"."Int" NOT IN (@nullableInts1, @nullableInts2) """); } @@ -628,25 +609,19 @@ public override async Task Parameter_collection_of_nullable_ints_Contains_nullab AssertSql( """ -@nullableInts_without_nulls='[999]' (Size = 5) +@nullableInts1='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableInt" IN ( - SELECT "n"."value" - FROM json_each(@nullableInts_without_nulls) AS "n" -) OR "p"."NullableInt" IS NULL +WHERE "p"."NullableInt" IS NULL OR "p"."NullableInt" = @nullableInts1 """, // """ -@nullableInts_without_nulls='[999]' (Size = 5) +@nullableInts1='999' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableInt" NOT IN ( - SELECT "n"."value" - FROM json_each(@nullableInts_without_nulls) AS "n" -) AND "p"."NullableInt" IS NOT NULL +WHERE "p"."NullableInt" IS NOT NULL AND "p"."NullableInt" <> @nullableInts1 """); } @@ -656,25 +631,21 @@ public override async Task Parameter_collection_of_strings_Contains_string(bool AssertSql( """ -@strings='["10","999"]' (Size = 12) +@strings1='10' (Size = 2) +@strings2='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."String" IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +WHERE "p"."String" IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 12) +@strings1='10' (Size = 2) +@strings2='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."String" NOT IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +WHERE "p"."String" NOT IN (@strings1, @strings2) """); } @@ -684,25 +655,21 @@ public override async Task Parameter_collection_of_strings_Contains_nullable_str AssertSql( """ -@strings='["10","999"]' (Size = 12) +@strings1='10' (Size = 2) +@strings2='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableString" IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +WHERE "p"."NullableString" IN (@strings1, @strings2) """, // """ -@strings='["10","999"]' (Size = 12) +@strings1='10' (Size = 2) +@strings2='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableString" NOT IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) OR "p"."NullableString" IS NULL +WHERE "p"."NullableString" NOT IN (@strings1, @strings2) OR "p"."NullableString" IS NULL """); } @@ -712,25 +679,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_str AssertSql( """ -@strings='["10",null]' (Size = 11) +@strings1='10' (Size = 2) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."String" IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +WHERE "p"."String" = @strings1 """, // """ -@strings_without_nulls='["10"]' (Size = 6) +@strings1='10' (Size = 2) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."String" NOT IN ( - SELECT "s"."value" - FROM json_each(@strings_without_nulls) AS "s" -) +WHERE "p"."String" <> @strings1 """); } @@ -740,25 +701,19 @@ public override async Task Parameter_collection_of_nullable_strings_Contains_nul AssertSql( """ -@strings_without_nulls='["999"]' (Size = 7) +@strings1='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableString" IN ( - SELECT "s"."value" - FROM json_each(@strings_without_nulls) AS "s" -) OR "p"."NullableString" IS NULL +WHERE "p"."NullableString" IS NULL OR "p"."NullableString" = @strings1 """, // """ -@strings_without_nulls='["999"]' (Size = 7) +@strings1='999' (Size = 3) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableString" NOT IN ( - SELECT "s"."value" - FROM json_each(@strings_without_nulls) AS "s" -) AND "p"."NullableString" IS NOT NULL +WHERE "p"."NullableString" IS NOT NULL AND "p"."NullableString" <> @strings1 """); } @@ -768,14 +723,12 @@ public override async Task Parameter_collection_of_DateTimes_Contains(bool async AssertSql( """ -@dateTimes='["2020-01-10 12:30:00","9999-01-01 00:00:00"]' (Size = 45) +@dateTimes1='2020-01-10T12:30:00.0000000Z' (DbType = DateTime) +@dateTimes2='9999-01-01T00:00:00.0000000Z' (DbType = DateTime) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."DateTime" IN ( - SELECT "d"."value" - FROM json_each(@dateTimes) AS "d" -) +WHERE "p"."DateTime" IN (@dateTimes1, @dateTimes2) """); } @@ -785,14 +738,11 @@ public override async Task Parameter_collection_of_bools_Contains(bool async) AssertSql( """ -@bools='[true]' (Size = 6) +@bools1='True' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Bool" IN ( - SELECT "b"."value" - FROM json_each(@bools) AS "b" -) +WHERE "p"."Bool" = @bools1 """); } @@ -802,14 +752,12 @@ public override async Task Parameter_collection_of_enums_Contains(bool async) AssertSql( """ -@enums='[0,3]' (Size = 5) +@enums1='0' +@enums2='3' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Enum" IN ( - SELECT "e"."value" - FROM json_each(@enums) AS "e" -) +WHERE "p"."Enum" IN (@enums1, @enums2) """); } @@ -821,10 +769,7 @@ public override async Task Parameter_collection_null_Contains(bool async) """ SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(NULL) AS "i" -) +WHERE 0 """); } @@ -833,7 +778,7 @@ public override async Task Parameter_collection_Contains_with_EF_Constant(bool a await base.Parameter_collection_Contains_with_EF_Constant(async); AssertSql( - """ + """ SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE "p"."Id" IN (2, 999, 1000) @@ -870,6 +815,14 @@ SELECT COUNT(*) """); } + // nothing to test here + public override Task Parameter_collection_Count_with_huge_number_of_values(bool async) + => base.Parameter_collection_Count_with_huge_number_of_values(async); + + // nothing to test here + public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(bool async) + => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values(async); + public override async Task Column_collection_of_ints_Contains(bool async) { await base.Column_collection_of_ints_Contains(async); @@ -1466,14 +1419,15 @@ public override async Task Column_collection_Join_parameter_collection(bool asyn AssertSql( """ -@ints='[11,111]' (Size = 8) +@ints1='11' +@ints2='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM json_each("p"."Ints") AS "i" - INNER JOIN json_each(@ints) AS "i0" ON "i"."value" = "i0"."value") = 2 + INNER JOIN (SELECT @ints1 AS "Value" UNION ALL VALUES (@ints2)) AS "i0" ON "i"."value" = "i0"."Value") = 2 """); } @@ -1501,15 +1455,18 @@ await Assert.ThrowsAsync( AssertSql( """ -@ints='[11,111]' (Size = 8) +@ints1='11' +@ints2='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM ( - SELECT 1 - FROM json_each(@ints) AS "i" + SELECT * FROM ( + SELECT 1 + FROM (SELECT @ints1 AS "Value" UNION ALL VALUES (@ints2)) AS "i" + ) UNION ALL SELECT 1 FROM json_each("p"."Ints") AS "i0" @@ -1539,7 +1496,8 @@ public override async Task Column_collection_Union_parameter_collection(bool asy AssertSql( """ -@ints='[11,111]' (Size = 8) +@ints1='11' +@ints2='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" @@ -1549,8 +1507,9 @@ SELECT COUNT(*) SELECT "i"."value" FROM json_each("p"."Ints") AS "i" UNION - SELECT "i0"."value" - FROM json_each(@ints) AS "i0" + SELECT * FROM ( + SELECT @ints1 AS "Value" UNION ALL VALUES (@ints2) + ) ) AS "u") = 2 """); } @@ -1569,7 +1528,9 @@ SELECT COUNT(*) SELECT "i"."value" FROM json_each("p"."Ints") AS "i" INTERSECT - SELECT CAST(11 AS INTEGER) AS "Value" UNION ALL VALUES (111) + SELECT * FROM ( + SELECT CAST(11 AS INTEGER) AS "Value" UNION ALL VALUES (111) + ) ) AS "i0") = 2 """); } @@ -1585,7 +1546,9 @@ public override async Task Inline_collection_Except_column_collection(bool async WHERE ( SELECT COUNT(*) FROM ( - SELECT CAST(11 AS INTEGER) AS "Value" UNION ALL VALUES (111) + SELECT * FROM ( + SELECT CAST(11 AS INTEGER) AS "Value" UNION ALL VALUES (111) + ) EXCEPT SELECT "i"."value" AS "Value" FROM json_each("p"."Ints") AS "i" @@ -1667,19 +1630,20 @@ public override async Task Parameter_collection_in_subquery_Count_as_compiled_qu AssertSql( """ -@ints='[10,111]' (Size = 8) +@ints1='10' +@ints2='111' SELECT COUNT(*) FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM ( - SELECT "i"."value" AS "value0" - FROM json_each(@ints) AS "i" - ORDER BY "i"."key" + SELECT "i"."Value" AS "Value0" + FROM (SELECT 1 AS "_ord", @ints1 AS "Value" UNION ALL VALUES (2, @ints2)) AS "i" + ORDER BY "i"."_ord" LIMIT -1 OFFSET 1 ) AS "i0" - WHERE "i0"."value0" > "p"."Id") = 1 + WHERE "i0"."Value0" > "p"."Id") = 1 """); } @@ -1696,22 +1660,23 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@ints='[10,111]' (Size = 8) +@ints1='10' +@ints2='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM ( - SELECT "i1"."value" + SELECT "i1"."Value" FROM ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" - ORDER BY "i"."key" + SELECT "i"."Value" + FROM (SELECT 1 AS "_ord", @ints1 AS "Value" UNION ALL VALUES (2, @ints2)) AS "i" + ORDER BY "i"."_ord" LIMIT -1 OFFSET 1 ) AS "i1" UNION - SELECT "i0"."value" + SELECT "i0"."value" AS "Value" FROM json_each("p"."Ints") AS "i0" ) AS "u") = 3 """); @@ -1723,17 +1688,16 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 5) +@Skip1='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM ( - SELECT "s"."value" - FROM json_each(@Skip) AS "s" + SELECT @Skip1 AS "Value" UNION - SELECT "i"."value" + SELECT "i"."value" AS "Value" FROM json_each("p"."Ints") AS "i" ) AS "u") = 3 """); @@ -1745,17 +1709,16 @@ public override async Task Parameter_collection_in_subquery_Union_column_collect AssertSql( """ -@Skip='[111]' (Size = 5) +@Skip1='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE ( SELECT COUNT(*) FROM ( - SELECT "s"."value" - FROM json_each(@Skip) AS "s" + SELECT @Skip1 AS "Value" UNION - SELECT "i2"."value" + SELECT "i2"."value" AS "Value" FROM ( SELECT "i1"."value" FROM ( @@ -1787,7 +1750,8 @@ public override async Task Column_collection_in_subquery_Union_parameter_collect AssertSql( """ -@ints='[10,111]' (Size = 8) +@ints1='10' +@ints2='111' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" @@ -1802,8 +1766,9 @@ ORDER BY "i"."key" LIMIT -1 OFFSET 1 ) AS "i1" UNION - SELECT "i0"."value" - FROM json_each(@ints) AS "i0" + SELECT * FROM ( + SELECT @ints1 AS "Value" UNION ALL VALUES (@ints2) + ) ) AS "u") = 3 """); } @@ -1923,21 +1888,19 @@ public override async Task Nested_contains_with_Lists_and_no_inferred_type_mappi AssertSql( """ -@ints='[1,2,3]' (Size = 7) -@strings='["one","two","three"]' (Size = 21) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 3) +@strings2='two' (Size = 3) +@strings3='three' (Size = 5) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE CASE - WHEN "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" - ) THEN 'one' + WHEN "p"."Int" IN (@ints1, @ints2, @ints3) THEN 'one' ELSE 'two' -END IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +END IN (@strings1, @strings2, @strings3) """); } @@ -1947,21 +1910,19 @@ public override async Task Nested_contains_with_arrays_and_no_inferred_type_mapp AssertSql( """ -@ints='[1,2,3]' (Size = 7) -@strings='["one","two","three"]' (Size = 21) +@ints1='1' +@ints2='2' +@ints3='3' +@strings1='one' (Size = 3) +@strings2='two' (Size = 3) +@strings3='three' (Size = 5) SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" WHERE CASE - WHEN "p"."Int" IN ( - SELECT "i"."value" - FROM json_each(@ints) AS "i" - ) THEN 'one' + WHEN "p"."Int" IN (@ints1, @ints2, @ints3) THEN 'one' ELSE 'two' -END IN ( - SELECT "s"."value" - FROM json_each(@strings) AS "s" -) +END IN (@strings1, @strings2, @strings3) """); } @@ -2014,25 +1975,21 @@ public override async Task Parameter_collection_of_structs_Contains_struct(bool AssertSql( """ -@values='[22,33]' (Size = 7) +@values1='22' +@values2='33' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."WrappedId" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."WrappedId" IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."WrappedId" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."WrappedId" NOT IN (@values1, @values2) """); } @@ -2042,25 +1999,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 7) +@values1='22' +@values2='33' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedId" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."NullableWrappedId" IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedId" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) OR "p"."NullableWrappedId" IS NULL +WHERE "p"."NullableWrappedId" NOT IN (@values1, @values2) OR "p"."NullableWrappedId" IS NULL """); } @@ -2070,25 +2023,21 @@ public override async Task Parameter_collection_of_structs_Contains_nullable_str AssertSql( """ -@values='[22,33]' (Size = 7) +@values1='22' +@values2='33' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedIdWithNullableComparer" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."NullableWrappedIdWithNullableComparer" IN (@values1, @values2) """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedId" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) OR "p"."NullableWrappedId" IS NULL +WHERE "p"."NullableWrappedId" NOT IN (@values1, @values2) OR "p"."NullableWrappedId" IS NULL """); } @@ -2098,25 +2047,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_str AssertSql( """ -@values='[null,22]' (Size = 9) +@values1='22' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."WrappedId" IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."WrappedId" = @values1 """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."WrappedId" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) +WHERE "p"."WrappedId" NOT IN (@values1, @values2) """); } @@ -2126,25 +2070,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4) +@values1='22' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedId" IN ( - SELECT "v"."value" - FROM json_each(@values_without_nulls) AS "v" -) OR "p"."NullableWrappedId" IS NULL +WHERE "p"."NullableWrappedId" IS NULL OR "p"."NullableWrappedId" = @values1 """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedId" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) OR "p"."NullableWrappedId" IS NULL +WHERE "p"."NullableWrappedId" NOT IN (@values1, @values2) OR "p"."NullableWrappedId" IS NULL """); } @@ -2154,25 +2093,20 @@ public override async Task Parameter_collection_of_nullable_structs_Contains_nul AssertSql( """ -@values_without_nulls='[22]' (Size = 4) +@values1='22' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedIdWithNullableComparer" IN ( - SELECT "v"."value" - FROM json_each(@values_without_nulls) AS "v" -) OR "p"."NullableWrappedIdWithNullableComparer" IS NULL +WHERE "p"."NullableWrappedIdWithNullableComparer" IS NULL OR "p"."NullableWrappedIdWithNullableComparer" = @values1 """, // """ -@values='[11,44]' (Size = 7) +@values1='11' +@values2='44' SELECT "p"."Id", "p"."Bool", "p"."Bools", "p"."DateTime", "p"."DateTimes", "p"."Enum", "p"."Enums", "p"."Int", "p"."Ints", "p"."NullableInt", "p"."NullableInts", "p"."NullableString", "p"."NullableStrings", "p"."NullableWrappedId", "p"."NullableWrappedIdWithNullableComparer", "p"."String", "p"."Strings", "p"."WrappedId" FROM "PrimitiveCollectionsEntity" AS "p" -WHERE "p"."NullableWrappedIdWithNullableComparer" NOT IN ( - SELECT "v"."value" - FROM json_each(@values) AS "v" -) OR "p"."NullableWrappedIdWithNullableComparer" IS NULL +WHERE "p"."NullableWrappedIdWithNullableComparer" NOT IN (@values1, @values2) OR "p"."NullableWrappedIdWithNullableComparer" IS NULL """); }