diff --git a/Directory.Packages.props b/Directory.Packages.props index fa4a353bf..919935edf 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,7 @@ - 10.0.0-preview.6.25321.102 - 10.0.0-preview.6.25321.102 + 10.0.0-preview.7.25352.2 + 10.0.0-preview.7.25351.105 9.0.3 diff --git a/src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs b/src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs index 928e75438..1ccd6b906 100644 --- a/src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs +++ b/src/EFCore.PG/Infrastructure/Internal/NpgsqlOptionsExtension.cs @@ -11,11 +11,25 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal; public class NpgsqlOptionsExtension : RelationalOptionsExtension { private DbContextOptionsExtensionInfo? _info; + private ParameterizedCollectionMode? _parameterizedCollectionMode; + private readonly List _userRangeDefinitions; private readonly List _enumDefinitions; - private Version? _postgresVersion; + // We override ParameterizedCollectionMode to set Parameter as the default instead of MultipleParameters, + // which is the EF relational default. In PostgreSQL using native array parameters is better, and the + // query plan problem can be mitigated by telling PostgreSQL to use a custom plan (see #3269). + + /// + /// 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 ParameterizedCollectionMode ParameterizedCollectionMode + => _parameterizedCollectionMode ?? ParameterizedCollectionMode.Parameter; + /// /// 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 @@ -132,6 +146,17 @@ public NpgsqlOptionsExtension(NpgsqlOptionsExtension copyFrom) public override int? MinBatchSize => base.MinBatchSize ?? 2; + // We need to override WithUseParameterizedCollectionMode since we override ParameterizedCollectionMode above + /// + public override RelationalOptionsExtension WithUseParameterizedCollectionMode(ParameterizedCollectionMode parameterizedCollectionMode) + { + var clone = (NpgsqlOptionsExtension)Clone(); + + clone._parameterizedCollectionMode = parameterizedCollectionMode; + + return clone; + } + /// /// 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 . diff --git a/src/EFCore.PG/Query/Internal/NpgsqlParameterBasedSqlProcessor.cs b/src/EFCore.PG/Query/Internal/NpgsqlParameterBasedSqlProcessor.cs index dbb97a5c4..6def82e2c 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlParameterBasedSqlProcessor.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlParameterBasedSqlProcessor.cs @@ -27,12 +27,9 @@ public NpgsqlParameterBasedSqlProcessor( /// 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 Optimize( - Expression queryExpression, - IReadOnlyDictionary parametersValues, - out bool canCache) + public override Expression Process(Expression queryExpression, CacheSafeParameterFacade parametersFacade) { - queryExpression = base.Optimize(queryExpression, parametersValues, out canCache); + queryExpression = base.Process(queryExpression, parametersFacade); queryExpression = new NpgsqlDeleteConvertingExpressionVisitor().Process(queryExpression); @@ -40,15 +37,6 @@ public override Expression Optimize( } /// - protected override Expression ProcessSqlNullability( - Expression selectExpression, - IReadOnlyDictionary parametersValues, - out bool canCache) - { - Check.NotNull(selectExpression, nameof(selectExpression)); - Check.NotNull(parametersValues, nameof(parametersValues)); - - return new NpgsqlSqlNullabilityProcessor(Dependencies, Parameters).Process( - selectExpression, parametersValues, out canCache); - } + protected override Expression ProcessSqlNullability(Expression selectExpression, CacheSafeParameterFacade parametersFacade) + => new NpgsqlSqlNullabilityProcessor(Dependencies, Parameters).Process(selectExpression, parametersFacade); } diff --git a/src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs b/src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs index 6424f37e5..e5ce083da 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs @@ -737,5 +737,5 @@ private static bool MayContainNulls(SqlExpression arrayExpression) // Note that we can check parameter values for null since we cache by the parameter nullability; but we cannot do the same for bool. private bool IsNull(SqlExpression? expression) => expression is SqlConstantExpression { Value: null } - || expression is SqlParameterExpression { Name: string parameterName } && ParameterValues[parameterName] is null; + || expression is SqlParameterExpression { Name: string parameterName } && ParametersFacade.IsParameterNull(parameterName); } diff --git a/src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs b/src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs index ff443b89e..082bd59b5 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs @@ -611,7 +611,7 @@ private bool TryTranslateStartsEndsWithContains( QueryContext queryContext, string baseParameterName, StartsEndsWithContains methodType) - => queryContext.ParameterValues[baseParameterName] switch + => queryContext.Parameters[baseParameterName] switch { null => null, diff --git a/src/Shared/Check.cs b/src/Shared/Check.cs index 05c1e3dde..054131384 100644 --- a/src/Shared/Check.cs +++ b/src/Shared/Check.cs @@ -1,4 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable enable + using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using JetBrains.Annotations; namespace Microsoft.EntityFrameworkCore.Utilities; @@ -8,13 +14,13 @@ internal static class Check { [ContractAnnotation("value:null => halt")] [return: NotNull] - public static T NotNull([NoEnumeration] [AllowNull] [NotNull] T value, [InvokerParameterName] string parameterName) + public static T NotNull( + [NoEnumeration, AllowNull, NotNull] T value, + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { if (value is null) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentNullException(parameterName); + ThrowArgumentNull(parameterName); } return value; @@ -23,59 +29,52 @@ public static T NotNull([NoEnumeration] [AllowNull] [NotNull] T value, [Invok [ContractAnnotation("value:null => halt")] public static IReadOnlyList NotEmpty( [NotNull] IReadOnlyList? value, - [InvokerParameterName] string parameterName) + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { NotNull(value, parameterName); if (value.Count == 0) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentException(AbstractionsStrings.CollectionArgumentIsEmpty(parameterName)); + ThrowNotEmpty(parameterName); } return value; } [ContractAnnotation("value:null => halt")] - public static string NotEmpty([NotNull] string? value, [InvokerParameterName] string parameterName) + public static string NotEmpty( + [NotNull] string? value, + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { - if (value is null) - { - NotEmpty(parameterName, nameof(parameterName)); - throw new ArgumentNullException(parameterName); - } + NotNull(value, parameterName); - if (value.Trim().Length == 0) + if (value.AsSpan().Trim().Length == 0) { - NotEmpty(parameterName, nameof(parameterName)); - throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName)); + ThrowStringArgumentEmpty(parameterName); } return value; } - public static string? NullButNotEmpty(string? value, [InvokerParameterName] string parameterName) + public static IReadOnlyCollection? NullButNotEmpty( + IReadOnlyCollection? value, + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { - if (value is not null && value.Length == 0) + if (value is not null && value.Count == 0) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName)); + ThrowStringArgumentEmpty(parameterName); } return value; } - public static IReadOnlyCollection? NullButNotEmpty( - IReadOnlyCollection? value, - [InvokerParameterName] string parameterName) + public static string? NullButNotEmpty( + string? value, + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { - if (value is { Count: 0 }) + if (value is not null && value.Length == 0) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName)); + ThrowStringArgumentEmpty(parameterName); } return value; @@ -83,16 +82,17 @@ public static string NotEmpty([NotNull] string? value, [InvokerParameterName] st public static IReadOnlyList HasNoNulls( [NotNull] IReadOnlyList? value, - [InvokerParameterName] string parameterName) + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") where T : class { NotNull(value, parameterName); - if (value.Any(e => e is null)) + for (var i = 0; i < value.Count; i++) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentException(parameterName); + if (value[i] is null) + { + ThrowArgumentException(parameterName, parameterName); + } } return value; @@ -100,31 +100,52 @@ public static IReadOnlyList HasNoNulls( public static IReadOnlyList HasNoEmptyElements( [NotNull] IReadOnlyList? value, - [InvokerParameterName] string parameterName) + [InvokerParameterName, CallerArgumentExpression(nameof(value))] string parameterName = "") { NotNull(value, parameterName); - if (value.Any(s => string.IsNullOrWhiteSpace(s))) + for (var i = 0; i < value.Count; i++) { - NotEmpty(parameterName, nameof(parameterName)); - - throw new ArgumentException(AbstractionsStrings.CollectionArgumentHasEmptyElements(parameterName)); + if (string.IsNullOrWhiteSpace(value[i])) + { + ThrowCollectionHasEmptyElements(parameterName); + } } return value; } [Conditional("DEBUG")] - public static void DebugAssert([DoesNotReturnIf(false)] bool condition, string message) + public static void DebugAssert([DoesNotReturnIf(false)] bool condition, [CallerArgumentExpression(nameof(condition))] string message = "") { if (!condition) { - throw new Exception($"Check.DebugAssert failed: {message}"); + throw new UnreachableException($"Check.DebugAssert failed: {message}"); } } [Conditional("DEBUG")] [DoesNotReturn] public static void DebugFail(string message) - => throw new Exception($"Check.DebugFail failed: {message}"); + => throw new UnreachableException($"Check.DebugFail failed: {message}"); + + [DoesNotReturn] + private static void ThrowArgumentNull(string parameterName) + => throw new ArgumentNullException(parameterName); + + [DoesNotReturn] + private static void ThrowNotEmpty(string parameterName) + => throw new ArgumentException(AbstractionsStrings.CollectionArgumentIsEmpty, parameterName); + + [DoesNotReturn] + private static void ThrowStringArgumentEmpty(string parameterName) + => throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty, parameterName); + + [DoesNotReturn] + private static void ThrowCollectionHasEmptyElements(string parameterName) + => throw new ArgumentException(AbstractionsStrings.CollectionArgumentHasEmptyElements, parameterName); + + [DoesNotReturn] + private static void ThrowArgumentException(string message, string parameterName) + => throw new ArgumentException(message, parameterName); } diff --git a/test/EFCore.PG.FunctionalTests/Query/AdHocMiscellaneousQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/AdHocMiscellaneousQueryNpgsqlTest.cs index d7e4c45a2..52e8c1920 100644 --- a/test/EFCore.PG.FunctionalTests/Query/AdHocMiscellaneousQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/AdHocMiscellaneousQueryNpgsqlTest.cs @@ -7,9 +7,9 @@ public class AdHocMiscellaneousQueryNpgsqlTest(NonSharedFixture fixture) : AdHoc protected override ITestStoreFactory TestStoreFactory => NpgsqlTestStoreFactory.Instance; - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) { - new NpgsqlDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); + new NpgsqlDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); return optionsBuilder; } diff --git a/test/EFCore.PG.FunctionalTests/Query/CompatibilityQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/CompatibilityQueryNpgsqlTest.cs index 9acb50692..6b3ef1dae 100644 --- a/test/EFCore.PG.FunctionalTests/Query/CompatibilityQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/CompatibilityQueryNpgsqlTest.cs @@ -17,17 +17,21 @@ public async Task Array_contains_is_not_parameterized_with_array_on_redshift() { var ctx = CreateRedshiftContext(); - var numbers = new[] { 8, 9 }; - var result = await ctx.TestEntities.Where(e => numbers.Contains(e.SomeInt)).SingleAsync(); - Assert.Equal(1, result.Id); - - AssertSql( - """ -SELECT t."Id", t."SomeInt" -FROM "TestEntities" AS t -WHERE t."SomeInt" IN (?, ?) -LIMIT 2 -"""); + // https://github.com/dotnet/efcore/issues/36311 + await Assert.ThrowsAsync(async () => + { + var numbers = new[] { 8, 9 }; + var result = await ctx.TestEntities.Where(e => numbers.Contains(e.SomeInt)).SingleAsync(); + Assert.Equal(1, result.Id); + + AssertSql( + """ + SELECT t."Id", t."SomeInt" + FROM "TestEntities" AS t + WHERE t."SomeInt" IN (?, ?) + LIMIT 2 + """); + }); } #region Support diff --git a/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsQueryNpgsqlTest.cs index 4cc5b4865..6a20b5a05 100644 --- a/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsQueryNpgsqlTest.cs @@ -20,8 +20,4 @@ public override Task GroupJoin_client_method_in_OrderBy(bool async) CoreStrings.QueryUnableToTranslateMethod( "Microsoft.EntityFrameworkCore.Query.ComplexNavigationsQueryTestBase", "ClientMethodNullableInt")); - - public override Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) - => Assert.ThrowsAsync( - async () => await base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async)); } diff --git a/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryNpgsqlTest.cs index 5cfa5cda7..fc8c7346a 100644 --- a/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryNpgsqlTest.cs @@ -30,10 +30,6 @@ public override Task GroupJoin_client_method_in_OrderBy(bool async) "Microsoft.EntityFrameworkCore.Query.ComplexNavigationsQueryTestBase", "ClientMethodNullableInt")); - public override Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) - => Assert.ThrowsAsync( - async () => await base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async)); - [ConditionalTheory(Skip = "https://github.com/dotnet/efcore/issues/26104")] public override Task GroupBy_aggregate_where_required_relationship(bool async) => base.GroupBy_aggregate_where_required_relationship(async); diff --git a/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs index d63e0da48..8ff3998c6 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs @@ -5,6 +5,13 @@ namespace Microsoft.EntityFrameworkCore.Query; public class NonSharedPrimitiveCollectionsQueryNpgsqlTest(NonSharedFixture fixture) : NonSharedPrimitiveCollectionsQueryRelationalTestBase(fixture) { + protected override DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode) + { + new NpgsqlDbContextOptionsBuilder(optionsBuilder).UseParameterizedCollectionMode(parameterizedCollectionMode); + + return optionsBuilder; + } + #region Support for specific element types // Since we just use arrays for primitive collections, there's no need to test each and every element type; arrays are fully typed @@ -95,20 +102,6 @@ LIMIT 2 """); } - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToConstants(DbContextOptionsBuilder optionsBuilder) - { - new NpgsqlDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToConstants(); - - return optionsBuilder; - } - - protected override DbContextOptionsBuilder SetTranslateParameterizedCollectionsToParameters(DbContextOptionsBuilder optionsBuilder) - { - new NpgsqlDbContextOptionsBuilder(optionsBuilder).TranslateParameterizedCollectionsToParameters(); - - return optionsBuilder; - } - protected override ITestStoreFactory TestStoreFactory => NpgsqlTestStoreFactory.Instance; } diff --git a/test/EFCore.PG.FunctionalTests/Query/NorthwindAggregateOperatorsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NorthwindAggregateOperatorsQueryNpgsqlTest.cs index 2e6d826e1..891df2ce4 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NorthwindAggregateOperatorsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NorthwindAggregateOperatorsQueryNpgsqlTest.cs @@ -15,6 +15,22 @@ public NorthwindAggregateOperatorsQueryNpgsqlTest( Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + // https://github.com/dotnet/efcore/issues/36311 + public override Task Contains_with_parameter_list_value_type_id(bool async) + => Assert.ThrowsAsync(() => base.Contains_with_parameter_list_value_type_id(async)); + + // https://github.com/dotnet/efcore/issues/36311 + public override Task IReadOnlySet_Contains_with_parameter(bool async) + => Assert.ThrowsAsync(() => base.IReadOnlySet_Contains_with_parameter(async)); + + // https://github.com/dotnet/efcore/issues/36311 + public override Task List_Contains_with_parameter_list(bool async) + => Assert.ThrowsAsync(() => base.List_Contains_with_parameter_list(async)); + + // https://github.com/dotnet/efcore/issues/36311 + public override Task IImmutableSet_Contains_with_parameter(bool async) + => Assert.ThrowsAsync(() => base.IImmutableSet_Contains_with_parameter(async)); + // Overriding to add equality tolerance because of floating point precision public override async Task Average_over_max_subquery(bool async) { diff --git a/test/EFCore.PG.FunctionalTests/Query/NorthwindMiscellaneousQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NorthwindMiscellaneousQueryNpgsqlTest.cs index d4d4eca64..05b05157f 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NorthwindMiscellaneousQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NorthwindMiscellaneousQueryNpgsqlTest.cs @@ -18,6 +18,10 @@ public NorthwindMiscellaneousQueryNpgsqlTest( Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + // https://github.com/dotnet/efcore/issues/36311 + public override Task Entity_equality_contains_with_list_of_null(bool async) + => Assert.ThrowsAsync(() => base.Entity_equality_contains_with_list_of_null(async)); + public override async Task Query_expression_with_to_string_and_contains(bool async) { await base.Query_expression_with_to_string_and_contains(async); diff --git a/test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs index 63b709e0a..c78b21399 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NorthwindWhereQueryNpgsqlTest.cs @@ -13,6 +13,10 @@ public NorthwindWhereQueryNpgsqlTest(NorthwindQueryNpgsqlFixture Assert.ThrowsAsync(() => base.Where_navigation_contains(async)); + public override async Task Where_compare_constructed_equal(bool async) { // Anonymous type to constant comparison. Issue #14672. diff --git a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs index 4ddb4ae83..5de647bc1 100644 --- a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs @@ -822,6 +822,24 @@ SELECT count(*)::int """); } + // The following test does nothing since we don't override NumberOfValuesForHugeParameterCollectionTests; + // the PG parameter limit is huge (ushort), so we don't need to test it. + 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); + + AssertSql(); + } + + // The following test does nothing since we don't override NumberOfValuesForHugeParameterCollectionTests; + // the PG parameter limit is huge (ushort), so we don't need to test it. + 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); + + AssertSql(); + } + [ConditionalTheory] // #3012 [MinimumPostgresVersion(14, 0)] // Multiranges were introduced in PostgreSQL 14 [MemberData(nameof(IsAsyncData))] diff --git a/test/EFCore.PG.FunctionalTests/Update/JsonUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Update/JsonUpdateNpgsqlTest.cs index e2fbb95be..eeb8abaa7 100644 --- a/test/EFCore.PG.FunctionalTests/Update/JsonUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Update/JsonUpdateNpgsqlTest.cs @@ -1095,8 +1095,8 @@ public override async Task Edit_two_properties_on_same_entity_updates_the_entire AssertSql( """ -@p0='{"TestBoolean":false,"TestBooleanCollection":[true,false],"TestByte":25,"TestByteArray":"","TestByteCollection":null,"TestCharacter":"h","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2323-04-03","TestDateOnlyCollection":["3234-01-23","4331-01-21"],"TestDateTime":"2100-11-11T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2200-11-11T12:34:56-05:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-123450.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInCollection1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.2345,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"00000000-0000-0000-0000-000000000000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-12,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Baz","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Two","TestNullableEnumWithIntConverter":-3,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":90,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-18,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.4,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"05:07:08.0000000","TestTimeOnlyCollection":["13:42:23.0000000","07:17:25.0000000"],"TestTimeSpan":"06:05:04.003","TestTimeSpanCollection":["10:09:08.007","-09:50:51.993"],"TestUnsignedInt16":12,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":12345,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567867,"TestUnsignedInt64Collection":[0,0,18446744073709551615]}' (Nullable = false) (DbType = Object) -@p1='{"TestBoolean":true,"TestBooleanCollection":[true,false],"TestByte":255,"TestByteArray":"AQID","TestByteCollection":null,"TestCharacter":"a","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2023-10-10","TestDateOnlyCollection":["1234-01-23","4321-01-21"],"TestDateTime":"2000-01-01T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2000-01-01T12:34:56-08:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-1234567890.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInReference1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.23456789,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"12345678-1234-4321-7777-987654321000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-1234,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Foo","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Three","TestNullableEnumWithIntConverter":2,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":78,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-128,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.234,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"11:12:13.0000000","TestTimeOnlyCollection":["11:42:23.0000000","07:17:27.0000000"],"TestTimeSpan":"10:09:08.007","TestTimeSpanCollection":["10:09:08.007","-09:50:51.993"],"TestUnsignedInt16":1234,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":1234565789,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567890123456789,"TestUnsignedInt64Collection":[0,0,18446744073709551615]}' (Nullable = false) (DbType = Object) +@p0='{"TestBoolean":false,"TestBooleanCollection":[true,false],"TestByte":25,"TestByteArray":"","TestByteCollection":null,"TestCharacter":"h","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2323-04-03","TestDateOnlyCollection":["3234-01-23","4331-01-21"],"TestDateTime":"2100-11-11T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2200-11-11T12:34:56-05:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-123450.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInCollection1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.2345,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"00000000-0000-0000-0000-000000000000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-12,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Baz","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Two","TestNullableEnumWithIntConverter":-3,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":90,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-18,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.4,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"05:07:08.0000000","TestTimeOnlyCollection":["13:42:23.0000000","07:17:25.0000000"],"TestTimeSpan":"06:05:04.003","TestTimeSpanCollection":["10:09:08.007","-09:50:51.993"],"TestUnsignedInt16":12,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":12345,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567867,"TestUnsignedInt64Collection":[0,0,9223372036854775807]}' (Nullable = false) (DbType = Object) +@p1='{"TestBoolean":true,"TestBooleanCollection":[true,false],"TestByte":255,"TestByteArray":"AQID","TestByteCollection":null,"TestCharacter":"a","TestCharacterCollection":["A","B","\u0022"],"TestDateOnly":"2023-10-10","TestDateOnlyCollection":["1234-01-23","4321-01-21"],"TestDateTime":"2000-01-01T12:34:56","TestDateTimeCollection":["2000-01-01T12:34:56","3000-01-01T12:34:56"],"TestDateTimeOffset":"2000-01-01T12:34:56-08:00","TestDateTimeOffsetCollection":["2000-01-01T12:34:56-08:00"],"TestDecimal":-1234567890.01,"TestDecimalCollection":[-1234567890.01],"TestDefaultString":"MyDefaultStringInReference1","TestDefaultStringCollection":["S1","\u0022S2\u0022","S3"],"TestDouble":-1.23456789,"TestDoubleCollection":[-1.23456789,1.23456789,0],"TestEnum":-1,"TestEnumCollection":[-1,-3,-7],"TestEnumWithIntConverter":2,"TestEnumWithIntConverterCollection":[-1,-3,-7],"TestGuid":"12345678-1234-4321-7777-987654321000","TestGuidCollection":["12345678-1234-4321-7777-987654321000"],"TestInt16":-1234,"TestInt16Collection":[-32768,0,32767],"TestInt32":32,"TestInt32Collection":[-2147483648,0,2147483647],"TestInt64":64,"TestInt64Collection":[-9223372036854775808,0,9223372036854775807],"TestMaxLengthString":"Foo","TestMaxLengthStringCollection":["S1","S2","S3"],"TestNullableEnum":-1,"TestNullableEnumCollection":[-1,null,-3,-7],"TestNullableEnumWithConverterThatHandlesNulls":"Three","TestNullableEnumWithIntConverter":2,"TestNullableEnumWithIntConverterCollection":[-1,null,-3,-7],"TestNullableInt32":78,"TestNullableInt32Collection":[null,-2147483648,0,null,2147483647,null],"TestSignedByte":-128,"TestSignedByteCollection":[-128,0,127],"TestSingle":-1.234,"TestSingleCollection":[-1.234,0,-1.234],"TestTimeOnly":"11:12:13.0000000","TestTimeOnlyCollection":["11:42:23.0000000","07:17:27.0000000"],"TestTimeSpan":"10:09:08.007","TestTimeSpanCollection":["10:09:08.007","-09:50:51.993"],"TestUnsignedInt16":1234,"TestUnsignedInt16Collection":[0,0,65535],"TestUnsignedInt32":1234565789,"TestUnsignedInt32Collection":[0,0,4294967295],"TestUnsignedInt64":1234567890123456789,"TestUnsignedInt64Collection":[0,0,9223372036854775807]}' (Nullable = false) (DbType = Object) @p2='1' UPDATE "JsonEntitiesAllTypes" SET "Collection" = jsonb_set("Collection", '{0}', @p0), "Reference" = @p1