From 319233f3ddd1e13e593b8827b06e07b33b4dd721 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Wed, 10 Dec 2025 12:42:53 +0100 Subject: [PATCH 1/2] Fix parameter limit (because of sp_executesql). --- .../Query/Internal/SqlServerSqlNullabilityProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs index 1e7b0507ad2..4043707dc4d 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs @@ -16,7 +16,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerSqlNullabilityProcessor : SqlNullabilityProcessor { - private const int MaxParameterCount = 2100; + private const int MaxParameterCount = 2100 - 2; private static readonly bool UseOldBehavior37151 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37151", out var enabled) && enabled; From bce281d2cdafe20da6c4d3ccc203dafa74f03ae3 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Wed, 10 Dec 2025 14:04:37 +0100 Subject: [PATCH 2/2] Add tests. --- .../SqlServerSqlNullabilityProcessor.cs | 26 ++++++++++--------- .../PrimitiveCollectionsQuerySqlServerTest.cs | 24 +++++++++++++++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs index 4043707dc4d..d4b1819d21d 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs @@ -16,7 +16,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; /// public class SqlServerSqlNullabilityProcessor : SqlNullabilityProcessor { - private const int MaxParameterCount = 2100 - 2; + private int MaxParameterCount => UseOldBehavior37336 ? 2100 : 2100 - 2; private static readonly bool UseOldBehavior37151 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37151", out var enabled) && enabled; @@ -24,6 +24,9 @@ public class SqlServerSqlNullabilityProcessor : SqlNullabilityProcessor private static readonly bool UseOldBehavior37185 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37185", out var enabled) && enabled; + private static readonly bool UseOldBehavior37336 = + AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue37336", out var enabled) && enabled; + /// /// 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 @@ -303,17 +306,16 @@ protected override SqlExpression VisitIn(InExpression inExpression, bool allowOp /// protected override int CalculateParameterBucketSize(int count, RelationalTypeMapping elementTypeMapping) - => count switch - { - <= 5 => 1, - <= 150 => 10, - <= 750 => 50, - <= 2000 => 100, - <= 2070 => 10, // try not to over-pad as we approach that limit - <= MaxParameterCount when UseOldBehavior37151 => 0, - <= MaxParameterCount => 1, // just don't pad between 2070 and 2100, to minimize the crazy - _ => 200, - }; + { + if (count <= 5) return 1; + if (count <= 150) return 10; + if (count <= 750) return 50; + if (count <= 2000) return 100; + if (count <= 2070) return 10; // try not to over-pad as we approach that limit + if (count <= MaxParameterCount && UseOldBehavior37151) return 0; + if (count <= MaxParameterCount) return 1; // just don't pad between 2070 and 2100, to minimize the crazy + return 200; + } private bool TryHandleOverLimitParameters( SqlParameterExpression valuesParameter, diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs index d959d170c78..0709a396445 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs @@ -2420,6 +2420,30 @@ public virtual async Task Parameter_collection_of_ints_Contains_int_2071_values( Assert.Contains("@ints2071)", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); } + [ConditionalTheory] + [InlineData(2098)] + [InlineData(2099)] + [InlineData(2100)] + public virtual Task Parameter_collection_of_ints_Contains_int_parameters_limit(int count) + { + var ints = Enumerable.Range(10, count); + + // no exception from SQL Server is a pass + return AssertQuery(ss => ss.Set().Where(c => ints.Contains(c.Int))); + } + + [ConditionalTheory] + [InlineData(2098)] + [InlineData(2099)] + [InlineData(2100)] + public virtual Task Parameter_collection_Count_parameters_limit(int count) + { + var ids = Enumerable.Range(1000, count); + + // no exception from SQL Server is a pass + return AssertQuery(ss => ss.Set().Where(c => ids.Count(i => i > c.Id) > 0)); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType());