diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs index 1e7b0507ad2..5ad31f1a0ef 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs @@ -416,8 +416,10 @@ public class ParametersCounter( ReferenceEquals(lhs, rhs) || (lhs is not null && rhs is not null && lhs.InvariantName == rhs.InvariantName + && lhs.Type == rhs.Type + && lhs.TypeMapping == rhs.TypeMapping && lhs.TranslationMode == rhs.TranslationMode), - x => HashCode.Combine(x.InvariantName, x.TranslationMode))); + x => HashCode.Combine(x.InvariantName, x.Type, x.TypeMapping, x.TranslationMode))); private readonly HashSet _visitedQueryParameters = new(EqualityComparer.Create( diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs index 0bb192a3ed1..38d9b4b2c02 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/PrimitiveCollectionsQueryCosmosTest.cs @@ -851,6 +851,10 @@ public override Task Parameter_collection_Count_with_huge_number_of_values_over_ public override Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter() => base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter(); + // nothing to test here + public override Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + => base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + // nothing to test here public override Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants() => base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants(); @@ -867,6 +871,10 @@ public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_ public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter() => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter(); + // nothing to test here + public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + // nothing to test here public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); diff --git a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs index 8850111e2b6..6884f0ad255 100644 --- a/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/PrimitiveCollectionsQueryTestBase.cs @@ -578,6 +578,26 @@ public virtual Task Parameter_collection_Count_with_huge_number_of_values_over_5 .Where(c => extra.Count(i => i > c.Id) > 0)); } + [ConditionalFact] + public virtual Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + if (NumberOfValuesForHugeParameterCollectionTests is null) + { + return Task.CompletedTask; + } + + var extra = Enumerable.Range(1000, (int)NumberOfValuesForHugeParameterCollectionTests / 3); + var ids = new[] { 2, 999 }; + + // Id will have a different type mapping here. + // Very specific, kind of fragile, but at least something. + // More info efcore#37185. + return AssertQuery(ss => ss.Set() + .Where(c => ids.Count(i => i > c.Id) > 0) + .Where(c => extra.Count(i => i > c.Id) > 0) + .Where(c => extra.Count(i => i > c.Int) > 0)); + } + [ConditionalFact] public virtual Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() { @@ -733,6 +753,30 @@ await AssertQuery(ss => ss.Set() .Where(c => !extra.Contains(c.Int))); } + [ConditionalFact] + public virtual async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + if (NumberOfValuesForHugeParameterCollectionTests is null) + { + return; + } + + var extra = Enumerable.Range(10, (int)NumberOfValuesForHugeParameterCollectionTests / 3).Append(1); + var ints = new[] { 10, 999 }; + + // Id will have a different type mapping here. + // Very specific, kind of fragile, but at least something. + // More info efcore#37185. + await AssertQuery(ss => ss.Set() + .Where(c => ints.Contains(c.Int)) + .Where(c => extra.Contains(c.Int)) + .Where(c => extra.Contains(c.Id))); + await AssertQuery(ss => ss.Set() + .Where(c => !ints.Contains(c.Int)) + .Where(c => !extra.Contains(c.Int)) + .Where(c => !extra.Contains(c.Id))); + } + [ConditionalFact] public virtual async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs index f033cab482a..46d2d7b1006 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQueryOldSqlServerTest.cs @@ -862,6 +862,13 @@ public override async Task Parameter_collection_Count_with_huge_number_of_values Assert.Contains("@ids2=", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + Assert.Contains("VALUES (2)", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants(); @@ -903,6 +910,14 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_huge_n Assert.Contains("@ints2=", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + Assert.DoesNotContain("OPENJSON", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + Assert.DoesNotContain("OPENJSON", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); + } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs index 5c1ca6de652..2192d4e2771 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServer160Test.cs @@ -870,6 +870,13 @@ public override async Task Parameter_collection_Count_with_huge_number_of_values Assert.Contains("@ids2=", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants(); @@ -911,6 +918,14 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_huge_n Assert.Contains("@ints2=", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + 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 Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs index c173aead092..6884e794775 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerJsonTypeTest.cs @@ -117,6 +117,13 @@ public override async Task Parameter_collection_Count_with_huge_number_of_values Assert.Contains("@ids2=", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants(); @@ -158,6 +165,14 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_huge_n Assert.Contains("@ints2=", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + 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 Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs index d959d170c78..8bc5a67cc68 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/PrimitiveCollectionsQuerySqlServerTest.cs @@ -893,6 +893,13 @@ public override async Task Parameter_collection_Count_with_huge_number_of_values Assert.Contains("@ids2=", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + Assert.Contains("OPENJSON(@ids) WITH ([value] int '$')", Fixture.TestSqlLoggerFactory.SqlStatements[0], StringComparison.Ordinal); + } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants(); @@ -934,6 +941,14 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_huge_n Assert.Contains("@ints2=", Fixture.TestSqlLoggerFactory.SqlStatements[1], StringComparison.Ordinal); } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + 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 Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() { await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs index 73041c1b9c1..999c446f4a7 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs @@ -875,6 +875,10 @@ public override Task Parameter_collection_Count_with_huge_number_of_values_over_ public override Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter() => base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter(); + // nothing to test here + public override Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + => base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + // nothing to test here public override Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants() => base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants(); @@ -891,6 +895,10 @@ public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_ public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter() => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter(); + // nothing to test here + public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + // nothing to test here public override Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() => base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants();