From 9fa2a387a294b90c3ed87cbbb8172a208e3b77d7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sun, 21 Sep 2025 09:59:40 +0200 Subject: [PATCH 1/3] Sync to EF 10.0.0-rc.2.25468.104 --- Directory.Packages.props | 4 +- .../ComplexTypeBulkUpdatesNpgsqlTest.cs | 304 -------- .../ComplexJsonBulkUpdateNpgsqlTest.cs | 656 ++++++++++++++++++ .../ComplexJsonCollectionNpgsqlTest.cs | 4 +- ...omplexJsonPrimitiveCollectionNpgsqlTest.cs | 85 +++ .../ComplexJsonProjectionNpgsqlTest.cs | 9 +- ...ComplexJsonStructuralEqualityNpgsqlTest.cs | 19 +- ...mplexTableSplittingBulkUpdateNpgsqlTest.cs | 488 +++++++++++++ ...exTableSplittingMiscellaneousNpgsqlTest.cs | 6 +- ...eSplittingPrimitiveCollectionNpgsqlTest.cs | 85 +++ ...mplexTableSplittingProjectionNpgsqlTest.cs | 32 +- ...leSplittingStructuralEqualityNpgsqlTest.cs | 29 +- .../NavigationsCollectionNpgsqlTest.cs | 28 +- .../NavigationsIncludeNpgsqlTest.cs | 36 +- .../NavigationsMiscellaneousNpgsqlTest.cs | 12 +- ...avigationsPrimitiveCollectionNpgsqlTest.cs | 166 +++++ .../NavigationsProjectionNpgsqlTest.cs | 46 +- .../NavigationsSetOperationsNpgsqlTest.cs | 12 +- ...NavigationsStructuralEqualityNpgsqlTest.cs | 54 +- .../OwnedJsonCollectionNpgsqlTest.cs | 17 +- .../OwnedJsonPrimitiveCollectionNpgsqlTest.cs | 85 +++ .../OwnedJsonProjectionNpgsqlTest.cs | 9 +- .../OwnedNavigationsCollectionNpgsqlTest.cs | 28 +- ...OwnedNavigationsMiscellaneousNpgsqlTest.cs | 12 +- ...avigationsPrimitiveCollectionNpgsqlTest.cs | 166 +++++ .../OwnedNavigationsProjectionNpgsqlTest.cs | 46 +- ...OwnedNavigationsSetOperationsNpgsqlTest.cs | 8 +- ...NavigationsStructuralEqualityNpgsqlTest.cs | 28 +- ...edTableSplittingMiscellaneousNpgsqlTest.cs | 18 +- ...eSplittingPrimitiveCollectionNpgsqlTest.cs | 135 ++++ ...OwnedTableSplittingProjectionNpgsqlTest.cs | 58 +- ...leSplittingStructuralEqualityNpgsqlTest.cs | 48 +- .../Query/PrecompiledQueryNpgsqlTest.cs | 4 +- .../Types/Miscellaneous/NpgsqlBoolTypeTest.cs | 109 +++ .../Miscellaneous/NpgsqlByteArrayTypeTest.cs | 111 +++ .../Types/Miscellaneous/NpgsqlGuidTypeTest.cs | 109 +++ .../Miscellaneous/NpgsqlStringTypeTest.cs | 109 +++ .../Types/Networking/NpgsqlInetTypeTest.cs | 111 +++ .../Types/Networking/NpgsqlMacaddrTypeTest.cs | 111 +++ .../Types/NpgsqlTypeFixture.cs | 6 + .../Types/Numeric/NpgsqlDecimalTypeTest.cs | 109 +++ .../Types/Numeric/NpgsqlDoubleTypeTest.cs | 109 +++ .../Types/Numeric/NpgsqlFloatTypeTest.cs | 109 +++ .../Types/Numeric/NpgsqlIntTypeTest.cs | 109 +++ .../Types/Numeric/NpgsqlLongTypeTest.cs | 109 +++ .../Types/Numeric/NpgsqlShortTypeTest.cs | 109 +++ .../Types/Temporal/NpgsqlDateOnlyTypeTest.cs | 109 +++ .../Temporal/NpgsqlDateTimeOffsetTypeTest.cs | 110 +++ .../NpgsqlDateTimeUnspecifiedTypeTest.cs | 111 +++ .../Temporal/NpgsqlDateTimeUtcTypeTest.cs | 109 +++ .../Types/Temporal/NpgsqlTimeOnlyTypeTest.cs | 109 +++ .../Types/Temporal/NpgsqlTimeSpanTypeTest.cs | 109 +++ 52 files changed, 4138 insertions(+), 576 deletions(-) delete mode 100644 test/EFCore.PG.FunctionalTests/BulkUpdates/ComplexTypeBulkUpdatesNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingPrimitiveCollectionNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/NpgsqlTypeFixture.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 9f8aafc12..ae8c8adaa 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,7 @@ - 10.0.0-rc.2.25431.101 - 10.0.0-rc.1.25431.101 + 10.0.0-rc.2.25468.104 + 10.0.0-rc.2.25468.104 9.0.3 diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/ComplexTypeBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/ComplexTypeBulkUpdatesNpgsqlTest.cs deleted file mode 100644 index 9e9c4b732..000000000 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/ComplexTypeBulkUpdatesNpgsqlTest.cs +++ /dev/null @@ -1,304 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.BulkUpdates; - -public class ComplexTypeBulkUpdatesNpgsqlTest( - ComplexTypeBulkUpdatesNpgsqlTest.ComplexTypeBulkUpdatesNpgsqlFixture fixture, - ITestOutputHelper testOutputHelper) - : ComplexTypeBulkUpdatesRelationalTestBase(fixture, testOutputHelper) -{ - public override async Task Delete_entity_type_with_complex_type(bool async) - { - await base.Delete_entity_type_with_complex_type(async); - - AssertSql( - """ -DELETE FROM "Customer" AS c -WHERE c."Name" = 'Monty Elias' -"""); - } - - public override async Task Delete_complex_type(bool async) - { - await base.Delete_complex_type(async); - - AssertSql(); - } - - public override async Task Update_property_inside_complex_type(bool async) - { - await base.Update_property_inside_complex_type(async); - - AssertExecuteUpdateSql( - """ -@p='12345' - -UPDATE "Customer" AS c -SET "ShippingAddress_ZipCode" = @p -WHERE c."ShippingAddress_ZipCode" = 7728 -"""); - } - - public override async Task Update_property_inside_nested_complex_type(bool async) - { - await base.Update_property_inside_nested_complex_type(async); - - AssertExecuteUpdateSql( - """ -@p='United States Modified' - -UPDATE "Customer" AS c -SET "ShippingAddress_Country_FullName" = @p -WHERE c."ShippingAddress_Country_Code" = 'US' -"""); - } - - public override async Task Update_multiple_properties_inside_multiple_complex_types_and_on_entity_type(bool async) - { - await base.Update_multiple_properties_inside_multiple_complex_types_and_on_entity_type(async); - - AssertExecuteUpdateSql( - """ -@p='54321' - -UPDATE "Customer" AS c -SET "Name" = c."Name" || 'Modified', - "ShippingAddress_ZipCode" = c."BillingAddress_ZipCode", - "BillingAddress_ZipCode" = @p -WHERE c."ShippingAddress_ZipCode" = 7728 -"""); - } - - public override async Task Update_projected_complex_type(bool async) - { - await base.Update_projected_complex_type(async); - - AssertExecuteUpdateSql( - """ -@p='12345' - -UPDATE "Customer" AS c -SET "ShippingAddress_ZipCode" = @p -"""); - } - - public override async Task Update_multiple_projected_complex_types_via_anonymous_type(bool async) - { - await base.Update_multiple_projected_complex_types_via_anonymous_type(async); - - AssertExecuteUpdateSql( - """ -@p='54321' - -UPDATE "Customer" AS c -SET "ShippingAddress_ZipCode" = c."BillingAddress_ZipCode", - "BillingAddress_ZipCode" = @p -"""); - } - - public override async Task Update_projected_complex_type_via_OrderBy_Skip(bool async) - { - await base.Update_projected_complex_type_via_OrderBy_Skip(async); - - AssertExecuteUpdateSql(); - } - - public override async Task Update_complex_type_to_parameter(bool async) - { - await base.Update_complex_type_to_parameter(async); - - AssertExecuteUpdateSql( - """ -@complex_type_p_AddressLine1='New AddressLine1' -@complex_type_p_AddressLine2='New AddressLine2' -@complex_type_p_Tags={ 'new_tag1' -'new_tag2' } (DbType = Object) -@complex_type_p_ZipCode='99999' (Nullable = true) -@complex_type_p_Code='FR' -@complex_type_p_FullName='France' - -UPDATE "Customer" AS c -SET "ShippingAddress_AddressLine1" = @complex_type_p_AddressLine1, - "ShippingAddress_AddressLine2" = @complex_type_p_AddressLine2, - "ShippingAddress_Tags" = @complex_type_p_Tags, - "ShippingAddress_ZipCode" = @complex_type_p_ZipCode, - "ShippingAddress_Country_Code" = @complex_type_p_Code, - "ShippingAddress_Country_FullName" = @complex_type_p_FullName -"""); - } - - public override async Task Update_nested_complex_type_to_parameter(bool async) - { - await base.Update_nested_complex_type_to_parameter(async); - - AssertExecuteUpdateSql( - """ -@complex_type_p_Code='FR' -@complex_type_p_FullName='France' - -UPDATE "Customer" AS c -SET "ShippingAddress_Country_Code" = @complex_type_p_Code, - "ShippingAddress_Country_FullName" = @complex_type_p_FullName -"""); - } - - public override async Task Update_complex_type_to_another_database_complex_type(bool async) - { - await base.Update_complex_type_to_another_database_complex_type(async); - - AssertExecuteUpdateSql( - """ -UPDATE "Customer" AS c -SET "ShippingAddress_AddressLine1" = c."BillingAddress_AddressLine1", - "ShippingAddress_AddressLine2" = c."BillingAddress_AddressLine2", - "ShippingAddress_Tags" = c."BillingAddress_Tags", - "ShippingAddress_ZipCode" = c."BillingAddress_ZipCode", - "ShippingAddress_Country_Code" = c."ShippingAddress_Country_Code", - "ShippingAddress_Country_FullName" = c."ShippingAddress_Country_FullName" -"""); - } - - public override async Task Update_complex_type_to_inline_without_lambda(bool async) - { - await base.Update_complex_type_to_inline_without_lambda(async); - - AssertExecuteUpdateSql( - """ -@complex_type_p_AddressLine1='New AddressLine1' -@complex_type_p_AddressLine2='New AddressLine2' -@complex_type_p_Tags={ 'new_tag1' -'new_tag2' } (DbType = Object) -@complex_type_p_ZipCode='99999' (Nullable = true) -@complex_type_p_Code='FR' -@complex_type_p_FullName='France' - -UPDATE "Customer" AS c -SET "ShippingAddress_AddressLine1" = @complex_type_p_AddressLine1, - "ShippingAddress_AddressLine2" = @complex_type_p_AddressLine2, - "ShippingAddress_Tags" = @complex_type_p_Tags, - "ShippingAddress_ZipCode" = @complex_type_p_ZipCode, - "ShippingAddress_Country_Code" = @complex_type_p_Code, - "ShippingAddress_Country_FullName" = @complex_type_p_FullName -"""); - } - - public override async Task Update_complex_type_to_inline_with_lambda(bool async) - { - await base.Update_complex_type_to_inline_with_lambda(async); - - AssertExecuteUpdateSql( - """ -UPDATE "Customer" AS c -SET "ShippingAddress_AddressLine1" = 'New AddressLine1', - "ShippingAddress_AddressLine2" = 'New AddressLine2', - "ShippingAddress_Tags" = ARRAY['new_tag1','new_tag2']::text[], - "ShippingAddress_ZipCode" = 99999, - "ShippingAddress_Country_Code" = 'FR', - "ShippingAddress_Country_FullName" = 'France' -"""); - } - - public override async Task Update_complex_type_to_another_database_complex_type_with_subquery(bool async) - { - await base.Update_complex_type_to_another_database_complex_type_with_subquery(async); - - AssertExecuteUpdateSql( - """ -@p='1' - -UPDATE "Customer" AS c0 -SET "ShippingAddress_AddressLine1" = c1."BillingAddress_AddressLine1", - "ShippingAddress_AddressLine2" = c1."BillingAddress_AddressLine2", - "ShippingAddress_Tags" = c1."BillingAddress_Tags", - "ShippingAddress_ZipCode" = c1."BillingAddress_ZipCode", - "ShippingAddress_Country_Code" = c1."ShippingAddress_Country_Code", - "ShippingAddress_Country_FullName" = c1."ShippingAddress_Country_FullName" -FROM ( - SELECT c."Id", c."BillingAddress_AddressLine1", c."BillingAddress_AddressLine2", c."BillingAddress_Tags", c."BillingAddress_ZipCode", c."ShippingAddress_Country_Code", c."ShippingAddress_Country_FullName" - FROM "Customer" AS c - ORDER BY c."Id" NULLS FIRST - OFFSET @p -) AS c1 -WHERE c0."Id" = c1."Id" -"""); - } - - public override async Task Update_collection_inside_complex_type(bool async) - { - await base.Update_collection_inside_complex_type(async); - - AssertExecuteUpdateSql( - """ -@p={ 'new_tag1' -'new_tag2' } (DbType = Object) - -UPDATE "Customer" AS c -SET "ShippingAddress_Tags" = @p -"""); - } - - public override async Task Update_complex_type_to_null(bool async) - { - await base.Update_complex_type_to_null(async); - - AssertExecuteUpdateSql( - """ -UPDATE "Customer" AS c -SET "OptionalAddress_AddressLine1" = NULL, - "OptionalAddress_AddressLine2" = NULL, - "OptionalAddress_Tags" = NULL, - "OptionalAddress_ZipCode" = NULL, - "OptionalAddress_Country_Code" = NULL, - "OptionalAddress_Country_FullName" = NULL -"""); - } - - public override async Task Update_complex_type_to_null_lambda(bool async) - { - await base.Update_complex_type_to_null_lambda(async); - - AssertExecuteUpdateSql( - """ -UPDATE "Customer" AS c -SET "OptionalAddress_AddressLine1" = NULL, - "OptionalAddress_AddressLine2" = NULL, - "OptionalAddress_Tags" = NULL, - "OptionalAddress_ZipCode" = NULL, - "OptionalAddress_Country_Code" = NULL, - "OptionalAddress_Country_FullName" = NULL -"""); - } - - public override async Task Update_complex_type_to_null_parameter(bool async) - { - await base.Update_complex_type_to_null_parameter(async); - - AssertExecuteUpdateSql( - """ -UPDATE "Customer" AS c -SET "OptionalAddress_AddressLine1" = NULL, - "OptionalAddress_AddressLine2" = NULL, - "OptionalAddress_Tags" = NULL, - "OptionalAddress_ZipCode" = NULL, - "OptionalAddress_Country_Code" = NULL, - "OptionalAddress_Country_FullName" = NULL -"""); - } - - [ConditionalFact] - public virtual void Check_all_tests_overridden() - => TestHelpers.AssertAllMethodsOverridden(GetType()); - - private void AssertExecuteUpdateSql(params string[] expected) - => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); - - private void AssertSql(params string[] expected) - => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); - - protected void ClearLog() - => Fixture.TestSqlLoggerFactory.Clear(); - - public class ComplexTypeBulkUpdatesNpgsqlFixture : ComplexTypeBulkUpdatesRelationalFixtureBase - { - protected override ITestStoreFactory TestStoreFactory - => NpgsqlTestStoreFactory.Instance; - } -} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs new file mode 100644 index 000000000..6075fcc6c --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs @@ -0,0 +1,656 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.ComplexJson; + +public class ComplexJsonBulkUpdateNpgsqlTest( + ComplexJsonNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : ComplexJsonBulkUpdateRelationalTestBase(fixture, testOutputHelper) +{ + // #region Delete + + public override async Task Delete_entity_with_associations() + { + await base.Delete_entity_with_associations(); + + AssertSql( + """ +@deletableEntity_Name='?' + +DELETE FROM "RootEntity" AS r +WHERE r."Name" = @deletableEntity_Name +"""); + } + +// public override async Task Delete_required_associate() +// { +// await base.Delete_required_associate(); + +// AssertSql(); +// } + +// public override async Task Delete_optional_associate() +// { +// await base.Delete_optional_associate(); + +// AssertSql(); +// } + +// #endregion Delete + +// #region Update properties + +// public override async Task Update_property_inside_associate() +// { +// await base.Update_property_inside_associate(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_property_inside_associate_with_special_chars() +// { +// await base.Update_property_inside_associate_with_special_chars(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.String', N'{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }') +// FROM [RootEntity] AS [r] +// WHERE JSON_VALUE([r].[RequiredAssociate], '$.String' RETURNING nvarchar(max)) = N'{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', N'{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }') +// FROM [RootEntity] AS [r] +// WHERE JSON_VALUE([r].[RequiredAssociate], '$.String') = N'{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' +// """); +// } +// } + +// public override async Task Update_property_inside_nested_associate() +// { +// await base.Update_property_inside_nested_associate(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.RequiredNestedAssociate.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_property_on_projected_associate() +// { +// await base.Update_property_on_projected_associate(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', @p) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_property_on_projected_associate_with_OrderBy_Skip() +// { +// await base.Update_property_on_projected_associate_with_OrderBy_Skip(); + +// AssertExecuteUpdateSql(); +// } + +// public override async Task Update_associate_with_null_required_property() +// { +// await base.Update_associate_with_null_required_property(); + +// AssertExecuteUpdateSql(); +// } + +// #endregion Update properties + +// #region Update association + +// public override async Task Update_associate_to_parameter() +// { +// await base.Update_associate_to_parameter(); + +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 277) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = @complex_type_p +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_nested_associate_to_parameter() +// { +// await base.Update_nested_associate_to_parameter(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 97) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.RequiredNestedAssociate', @complex_type_p) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 97) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate', JSON_QUERY(@complex_type_p)) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_associate_to_another_associate() +// { +// await base.Update_associate_to_another_associate(); + +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[OptionalAssociate] = [r].[RequiredAssociate] +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_nested_associate_to_another_nested_associate() +// { +// await base.Update_nested_associate_to_another_nested_associate(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.OptionalNestedAssociate', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate')) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.OptionalNestedAssociate', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate')) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_associate_to_inline() +// { +// await base.Update_associate_to_inline(); + +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 280) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = @complex_type_p +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_associate_to_inline_with_lambda() +// { +// await base.Update_associate_to_inline_with_lambda(); + +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = '{"Id":1000,"Int":70,"Ints":[1,2,4],"Name":"Updated associate name","String":"Updated associate string","NestedCollection":[],"OptionalNestedAssociate":null,"RequiredNestedAssociate":{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}}' +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_nested_associate_to_inline_with_lambda() +// { +// await base.Update_nested_associate_to_inline_with_lambda(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.RequiredNestedAssociate', CAST('{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}' AS json)) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate', JSON_QUERY('{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}')) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_associate_to_null() +// { +// await base.Update_associate_to_null(); + +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[OptionalAssociate] = NULL +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_associate_to_null_with_lambda() +// { +// await base.Update_associate_to_null_with_lambda(); + +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[OptionalAssociate] = NULL +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_associate_to_null_parameter() +// { +// await base.Update_associate_to_null_parameter(); + +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[OptionalAssociate] = NULL +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_required_nested_associate_to_null() +// { +// await base.Update_required_nested_associate_to_null(); + +// AssertExecuteUpdateSql(); +// } + +// #endregion Update association + +// #region Update collection + +// public override async Task Update_collection_to_parameter() +// { +// await base.Update_collection_to_parameter(); + +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 571) + +// UPDATE [r] +// SET [r].[AssociateCollection] = @complex_type_p +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_nested_collection_to_parameter() +// { +// await base.Update_nested_collection_to_parameter(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 201) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.NestedCollection', @complex_type_p) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @complex_type_p='?' (Size = 201) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY(@complex_type_p)) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_nested_collection_to_inline_with_lambda() +// { +// await base.Update_nested_collection_to_inline_with_lambda(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.NestedCollection', CAST('[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name1","String":"Updated nested string1"},{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}]' AS json)) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY('[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name1","String":"Updated nested string1"},{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}]')) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_nested_collection_to_another_nested_collection() +// { +// await base.Update_nested_collection_to_another_nested_collection(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.NestedCollection', JSON_QUERY([r].[OptionalAssociate], '$.NestedCollection')) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY([r].[OptionalAssociate], '$.NestedCollection')) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// } + +// public override async Task Update_collection_referencing_the_original_collection() +// { +// await base.Update_collection_referencing_the_original_collection(); + +// AssertExecuteUpdateSql(); +// } + +// public override async Task Update_inside_structural_collection() +// { +// await base.Update_inside_structural_collection(); + +// AssertExecuteUpdateSql(); +// } + +// #endregion Update collection + +// #region Update primitive collection + +// public override async Task Update_primitive_collection_to_constant() +// { +// await base.Update_primitive_collection_to_constant(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.Ints', CAST('[1,2,4]' AS json)) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints', JSON_QUERY(N'[1,2,4]')) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_primitive_collection_to_parameter() +// { +// await base.Update_primitive_collection_to_parameter(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @ints='?' (Size = 8000) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.Ints', @ints) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @ints='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints', JSON_QUERY(@ints)) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_primitive_collection_to_another_collection() +// { +// await base.Update_primitive_collection_to_another_collection(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [RequiredAssociate].modify('$.OptionalNestedAssociate.Ints', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate.Ints')) +// FROM [RootEntity] AS [r] +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.OptionalNestedAssociate.Ints', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate.Ints')) +// FROM [RootEntity] AS [r] +// """); +// } +// } + +// public override async Task Update_inside_primitive_collection() +// { +// await base.Update_inside_primitive_collection(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (DbType = Int32) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.Ints[1]', @p) +// FROM [RootEntity] AS [r] +// WHERE ( +// SELECT COUNT(*) +// FROM OPENJSON(JSON_QUERY([r].[RequiredAssociate], '$.Ints')) AS [i]) >= 2 +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (DbType = Int32) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints[1]', @p) +// FROM [RootEntity] AS [r] +// WHERE ( +// SELECT COUNT(*) +// FROM OPENJSON(JSON_QUERY([r].[RequiredAssociate], '$.Ints')) AS [i]) >= 2 +// """); +// } +// } + +// #endregion Update primitive collection + +// #region Multiple updates + +// public override async Task Update_multiple_properties_inside_same_associate() +// { +// await base.Update_multiple_properties_inside_same_associate(); + +// // Note that since two properties within the same JSON column are updated, SQL Server 2025 modify +// // is not used (it only supports modifying a single property) +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) +// @p0='?' (DbType = Int32) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY(JSON_MODIFY([r].[RequiredAssociate], '$.String', @p), '$.Int', @p0) +// FROM [RootEntity] AS [r] +// """); +// } + +// public override async Task Update_multiple_properties_inside_associates_and_on_entity_type() +// { +// await base.Update_multiple_properties_inside_associates_and_on_entity_type(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[Name] = [r].[Name] + N'Modified', +// [RequiredAssociate].modify('$.String', JSON_VALUE([r].[OptionalAssociate], '$.String' RETURNING nvarchar(max))), +// [OptionalAssociate].modify('$.RequiredNestedAssociate.String', @p) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[Name] = [r].[Name] + N'Modified', +// [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', JSON_VALUE([r].[OptionalAssociate], '$.String')), +// [r].[OptionalAssociate] = JSON_MODIFY([r].[OptionalAssociate], '$.RequiredNestedAssociate.String', @p) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// } + +// public override async Task Update_multiple_projected_associates_via_anonymous_type() +// { +// await base.Update_multiple_projected_associates_via_anonymous_type(); + +// if (Fixture.UsingJsonType) +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [RequiredAssociate].modify('$.String', JSON_VALUE([r].[OptionalAssociate], '$.String' RETURNING nvarchar(max))), +// [OptionalAssociate].modify('$.String', @p) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// else +// { +// AssertExecuteUpdateSql( +// """ +// @p='?' (Size = 4000) + +// UPDATE [r] +// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', JSON_VALUE([r].[OptionalAssociate], '$.String')), +// [r].[OptionalAssociate] = JSON_MODIFY([r].[OptionalAssociate], '$.String', @p) +// FROM [RootEntity] AS [r] +// WHERE [r].[OptionalAssociate] IS NOT NULL +// """); +// } +// } + +// #endregion Multiple updates + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs index 1b2b11b26..6911164ec 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs @@ -16,6 +16,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -72,10 +73,11 @@ public override async Task Distinct() WHERE ( SELECT count(*)::int FROM ( - SELECT DISTINCT r0."Id", r0."Int", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 + SELECT DISTINCT r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..88641ad57 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,85 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.ComplexJson; + +public class ComplexJsonPrimitiveCollectionNpgsqlTest(ComplexJsonNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : ComplexJsonPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] = 1 +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE 3 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE 2 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(i0.value), 0)::int + FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i0(value)) +FROM "RootEntity" AS r +WHERE ( + SELECT COALESCE(sum(i.value), 0)::int + FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs index a3f9936d8..f7df1de3f 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs @@ -191,11 +191,12 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q AssertSql( """ -SELECT r0."Id", r0."Int", r0."Name", r0."String", r0."NestedCollection", r0."OptionalNested", r0."RequiredNested" +SELECT r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r0."NestedCollection", r0."OptionalNested", r0."RequiredNested" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -211,11 +212,12 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer AssertSql( """ -SELECT n."Id", n."Int", n."Name", n."String" +SELECT n."Id", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE @@ -228,11 +230,12 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer AssertSql( """ -SELECT n."Id", n."Int", n."Name", n."String" +SELECT n."Id", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."OptionalRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs index b5e23aebd..c8cf22cf4 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs @@ -90,7 +90,7 @@ public override async Task Nested_with_inline() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE (r."RequiredRelated" -> 'RequiredNested') = '{"Id":1000,"Int":8,"Name":"Root1_RequiredRelated_RequiredNested","String":"foo"}' +WHERE (r."RequiredRelated" -> 'RequiredNested') = '{"Id":1000,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredRelated_RequiredNested","String":"foo"}' """); } @@ -128,7 +128,7 @@ public override async Task Nested_collection_with_inline() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE (r."RequiredRelated" -> 'NestedCollection') = '[{"Id":1002,"Int":8,"Name":"Root1_RequiredRelated_NestedCollection_1","String":"foo"},{"Id":1003,"Int":8,"Name":"Root1_RequiredRelated_NestedCollection_2","String":"foo"}]' +WHERE (r."RequiredRelated" -> 'NestedCollection') = '[{"Id":1002,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredRelated_NestedCollection_1","String":"foo"},{"Id":1003,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredRelated_NestedCollection_2","String":"foo"}]' """); } @@ -164,10 +164,11 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n - WHERE n."Id" = 1002 AND n."Int" = 8 AND n."Name" = 'Root1_RequiredRelated_NestedCollection_1' AND n."String" = 'foo') + WHERE n."Id" = 1002 AND n."Int" = 8 AND n."Ints" = ARRAY[1,2,3]::integer[] AND n."Name" = 'Root1_RequiredRelated_NestedCollection_1' AND n."String" = 'foo') """); } @@ -182,6 +183,7 @@ public override async Task Contains_with_parameter() """ @entity_equality_nested_Id='?' (DbType = Int32) @entity_equality_nested_Int='?' (DbType = Int32) +@entity_equality_nested_Ints='?' (DbType = Object) @entity_equality_nested_Name='?' @entity_equality_nested_String='?' @@ -192,10 +194,11 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n - WHERE n."Id" = @entity_equality_nested_Id AND n."Int" = @entity_equality_nested_Int AND n."Name" = @entity_equality_nested_Name AND n."String" = @entity_equality_nested_String) + WHERE n."Id" = @entity_equality_nested_Id AND n."Int" = @entity_equality_nested_Int AND n."Ints" = @entity_equality_nested_Ints AND n."Name" = @entity_equality_nested_Name AND n."String" = @entity_equality_nested_String) """); } @@ -208,6 +211,7 @@ public override async Task Contains_with_operators_composed_on_the_collection() @get_Item_Int='?' (DbType = Int32) @entity_equality_get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Int='?' (DbType = Int32) +@entity_equality_get_Item_Ints='?' (DbType = Object) @entity_equality_get_Item_Name='?' @entity_equality_get_Item_String='?' @@ -218,10 +222,11 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n - WHERE n."Int" > @get_Item_Int AND n."Id" = @entity_equality_get_Item_Id AND n."Int" = @entity_equality_get_Item_Int AND n."Name" = @entity_equality_get_Item_Name AND n."String" = @entity_equality_get_Item_String) + WHERE n."Int" > @get_Item_Int AND n."Id" = @entity_equality_get_Item_Id AND n."Int" = @entity_equality_get_Item_Int AND n."Ints" = @entity_equality_get_Item_Ints AND n."Name" = @entity_equality_get_Item_Name AND n."String" = @entity_equality_get_Item_String) """); } @@ -234,6 +239,7 @@ public override async Task Contains_with_nested_and_composed_operators() @get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Int='?' (DbType = Int32) +@entity_equality_get_Item_Ints='?' (DbType = Object) @entity_equality_get_Item_Name='?' @entity_equality_get_Item_String='?' @entity_equality_get_Item_NestedCollection='?' (DbType = Object) @@ -247,13 +253,14 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, "OptionalNested" jsonb, "RequiredNested" jsonb )) WITH ORDINALITY AS r0 - WHERE r0."Id" > @get_Item_Id AND r0."Id" = @entity_equality_get_Item_Id AND r0."Int" = @entity_equality_get_Item_Int AND r0."Name" = @entity_equality_get_Item_Name AND r0."String" = @entity_equality_get_Item_String AND (r0."NestedCollection") = @entity_equality_get_Item_NestedCollection AND (r0."OptionalNested") = @entity_equality_get_Item_OptionalNested AND (r0."RequiredNested") = @entity_equality_get_Item_RequiredNested) + WHERE r0."Id" > @get_Item_Id AND r0."Id" = @entity_equality_get_Item_Id AND r0."Int" = @entity_equality_get_Item_Int AND r0."Ints" = @entity_equality_get_Item_Ints AND r0."Name" = @entity_equality_get_Item_Name AND r0."String" = @entity_equality_get_Item_String AND (r0."NestedCollection") = @entity_equality_get_Item_NestedCollection AND (r0."OptionalNested") = @entity_equality_get_Item_OptionalNested AND (r0."RequiredNested") = @entity_equality_get_Item_RequiredNested) """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs new file mode 100644 index 000000000..9bc559554 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs @@ -0,0 +1,488 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.ComplexTableSplitting; + +public class ComplexTableSplittingBulkUpdateNpgsqlTest( + ComplexTableSplittingNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : ComplexTableSplittingBulkUpdateRelationalTestBase(fixture, testOutputHelper) +{ + #region Delete + + public override async Task Delete_entity_with_associations() + { + await base.Delete_entity_with_associations(); + + AssertSql( + """ +@deletableEntity_Name='?' + +DELETE FROM "RootEntity" AS r +WHERE r."Name" = @deletableEntity_Name +"""); + } + + public override async Task Delete_required_association() + { + await base.Delete_required_association(); + + AssertSql(); + } + + public override async Task Delete_optional_association() + { + await base.Delete_optional_association(); + + AssertSql(); + } + + #endregion Delete + + #region Update properties + + public override async Task Update_property_inside_association() + { + await base.Update_property_inside_association(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_String" = @p +"""); + } + + public override async Task Update_property_inside_association_with_special_chars() + { + await base.Update_property_inside_association_with_special_chars(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_String" = '{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }' +WHERE r."RequiredRelated_String" = '{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' +"""); + } + + public override async Task Update_property_inside_nested() + { + await base.Update_property_inside_nested(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_RequiredNested_String" = @p +"""); + } + + public override async Task Update_property_on_projected_association() + { + await base.Update_property_on_projected_association(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_String" = @p +"""); + } + + public override async Task Update_property_on_projected_association_with_OrderBy_Skip() + { + await base.Update_property_on_projected_association_with_OrderBy_Skip(); + + AssertExecuteUpdateSql(); + } + + #endregion Update properties + + #region Update association + + public override async Task Update_association_to_parameter() + { + await base.Update_association_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p_Id='?' (DbType = Int32) +@complex_type_p_Int='?' (DbType = Int32) +@complex_type_p_Ints='?' (DbType = Object) +@complex_type_p_Name='?' +@complex_type_p_String='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_Id" = @complex_type_p_Id, + "RequiredRelated_Int" = @complex_type_p_Int, + "RequiredRelated_Ints" = @complex_type_p_Ints, + "RequiredRelated_Name" = @complex_type_p_Name, + "RequiredRelated_String" = @complex_type_p_String, + "RequiredRelated_OptionalNested_Id" = @complex_type_p_Id, + "RequiredRelated_OptionalNested_Int" = @complex_type_p_Int, + "RequiredRelated_OptionalNested_Ints" = @complex_type_p_Ints, + "RequiredRelated_OptionalNested_Name" = @complex_type_p_Name, + "RequiredRelated_OptionalNested_String" = @complex_type_p_String, + "RequiredRelated_RequiredNested_Id" = @complex_type_p_Id, + "RequiredRelated_RequiredNested_Int" = @complex_type_p_Int, + "RequiredRelated_RequiredNested_Ints" = @complex_type_p_Ints, + "RequiredRelated_RequiredNested_Name" = @complex_type_p_Name, + "RequiredRelated_RequiredNested_String" = @complex_type_p_String +"""); + } + + public override async Task Update_nested_association_to_parameter() + { + await base.Update_nested_association_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p_Id='?' (DbType = Int32) +@complex_type_p_Int='?' (DbType = Int32) +@complex_type_p_Ints='?' (DbType = Object) +@complex_type_p_Name='?' +@complex_type_p_String='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_RequiredNested_Id" = @complex_type_p_Id, + "RequiredRelated_RequiredNested_Int" = @complex_type_p_Int, + "RequiredRelated_RequiredNested_Ints" = @complex_type_p_Ints, + "RequiredRelated_RequiredNested_Name" = @complex_type_p_Name, + "RequiredRelated_RequiredNested_String" = @complex_type_p_String +"""); + } + + public override async Task Update_association_to_another_association() + { + await base.Update_association_to_another_association(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated_Id" = r."RequiredRelated_Id", + "OptionalRelated_Int" = r."RequiredRelated_Int", + "OptionalRelated_Ints" = r."RequiredRelated_Ints", + "OptionalRelated_Name" = r."RequiredRelated_Name", + "OptionalRelated_String" = r."RequiredRelated_String", + "OptionalRelated_OptionalNested_Id" = r."OptionalRelated_OptionalNested_Id", + "OptionalRelated_OptionalNested_Int" = r."OptionalRelated_OptionalNested_Int", + "OptionalRelated_OptionalNested_Ints" = r."OptionalRelated_OptionalNested_Ints", + "OptionalRelated_OptionalNested_Name" = r."OptionalRelated_OptionalNested_Name", + "OptionalRelated_OptionalNested_String" = r."OptionalRelated_OptionalNested_String", + "OptionalRelated_RequiredNested_Id" = r."OptionalRelated_RequiredNested_Id", + "OptionalRelated_RequiredNested_Int" = r."OptionalRelated_RequiredNested_Int", + "OptionalRelated_RequiredNested_Ints" = r."OptionalRelated_RequiredNested_Ints", + "OptionalRelated_RequiredNested_Name" = r."OptionalRelated_RequiredNested_Name", + "OptionalRelated_RequiredNested_String" = r."OptionalRelated_RequiredNested_String" +"""); + } + + public override async Task Update_nested_association_to_another_nested_association() + { + await base.Update_nested_association_to_another_nested_association(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_OptionalNested_Id" = r."RequiredRelated_RequiredNested_Id", + "RequiredRelated_OptionalNested_Int" = r."RequiredRelated_RequiredNested_Int", + "RequiredRelated_OptionalNested_Ints" = r."RequiredRelated_RequiredNested_Ints", + "RequiredRelated_OptionalNested_Name" = r."RequiredRelated_RequiredNested_Name", + "RequiredRelated_OptionalNested_String" = r."RequiredRelated_RequiredNested_String" +"""); + } + + public override async Task Update_association_to_inline() + { + await base.Update_association_to_inline(); + + AssertExecuteUpdateSql( + """ +@complex_type_p_Id='?' (DbType = Int32) +@complex_type_p_Int='?' (DbType = Int32) +@complex_type_p_Ints='?' (DbType = Object) +@complex_type_p_Name='?' +@complex_type_p_String='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_Id" = @complex_type_p_Id, + "RequiredRelated_Int" = @complex_type_p_Int, + "RequiredRelated_Ints" = @complex_type_p_Ints, + "RequiredRelated_Name" = @complex_type_p_Name, + "RequiredRelated_String" = @complex_type_p_String, + "RequiredRelated_OptionalNested_Id" = @complex_type_p_Id, + "RequiredRelated_OptionalNested_Int" = @complex_type_p_Int, + "RequiredRelated_OptionalNested_Ints" = @complex_type_p_Ints, + "RequiredRelated_OptionalNested_Name" = @complex_type_p_Name, + "RequiredRelated_OptionalNested_String" = @complex_type_p_String, + "RequiredRelated_RequiredNested_Id" = @complex_type_p_Id, + "RequiredRelated_RequiredNested_Int" = @complex_type_p_Int, + "RequiredRelated_RequiredNested_Ints" = @complex_type_p_Ints, + "RequiredRelated_RequiredNested_Name" = @complex_type_p_Name, + "RequiredRelated_RequiredNested_String" = @complex_type_p_String +"""); + } + + public override async Task Update_association_to_inline_with_lambda() + { + await base.Update_association_to_inline_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_Id" = 1000, + "RequiredRelated_Int" = 70, + "RequiredRelated_Ints" = ARRAY[1,2,4]::integer[], + "RequiredRelated_Name" = 'Updated related name', + "RequiredRelated_String" = 'Updated related string', + "RequiredRelated_OptionalNested_Id" = NULL, + "RequiredRelated_OptionalNested_Int" = NULL, + "RequiredRelated_OptionalNested_Ints" = NULL, + "RequiredRelated_OptionalNested_Name" = NULL, + "RequiredRelated_OptionalNested_String" = NULL, + "RequiredRelated_RequiredNested_Id" = 1000, + "RequiredRelated_RequiredNested_Int" = 80, + "RequiredRelated_RequiredNested_Ints" = ARRAY[1,2,4]::integer[], + "RequiredRelated_RequiredNested_Name" = 'Updated nested name', + "RequiredRelated_RequiredNested_String" = 'Updated nested string' +"""); + } + + public override async Task Update_nested_association_to_inline_with_lambda() + { + await base.Update_nested_association_to_inline_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_RequiredNested_Id" = 1000, + "RequiredRelated_RequiredNested_Int" = 80, + "RequiredRelated_RequiredNested_Ints" = ARRAY[1,2,4]::integer[], + "RequiredRelated_RequiredNested_Name" = 'Updated nested name', + "RequiredRelated_RequiredNested_String" = 'Updated nested string' +"""); + } + + public override async Task Update_association_to_null() + { + await base.Update_association_to_null(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated_Id" = NULL, + "OptionalRelated_Int" = NULL, + "OptionalRelated_Ints" = NULL, + "OptionalRelated_Name" = NULL, + "OptionalRelated_String" = NULL, + "OptionalRelated_OptionalNested_Id" = NULL, + "OptionalRelated_OptionalNested_Int" = NULL, + "OptionalRelated_OptionalNested_Ints" = NULL, + "OptionalRelated_OptionalNested_Name" = NULL, + "OptionalRelated_OptionalNested_String" = NULL, + "OptionalRelated_RequiredNested_Id" = NULL, + "OptionalRelated_RequiredNested_Int" = NULL, + "OptionalRelated_RequiredNested_Ints" = NULL, + "OptionalRelated_RequiredNested_Name" = NULL, + "OptionalRelated_RequiredNested_String" = NULL +"""); + } + + public override async Task Update_association_to_null_with_lambda() + { + await base.Update_association_to_null_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated_Id" = NULL, + "OptionalRelated_Int" = NULL, + "OptionalRelated_Ints" = NULL, + "OptionalRelated_Name" = NULL, + "OptionalRelated_String" = NULL, + "OptionalRelated_OptionalNested_Id" = NULL, + "OptionalRelated_OptionalNested_Int" = NULL, + "OptionalRelated_OptionalNested_Ints" = NULL, + "OptionalRelated_OptionalNested_Name" = NULL, + "OptionalRelated_OptionalNested_String" = NULL, + "OptionalRelated_RequiredNested_Id" = NULL, + "OptionalRelated_RequiredNested_Int" = NULL, + "OptionalRelated_RequiredNested_Ints" = NULL, + "OptionalRelated_RequiredNested_Name" = NULL, + "OptionalRelated_RequiredNested_String" = NULL +"""); + } + + public override async Task Update_association_to_null_parameter() + { + await base.Update_association_to_null_parameter(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated_Id" = NULL, + "OptionalRelated_Int" = NULL, + "OptionalRelated_Ints" = NULL, + "OptionalRelated_Name" = NULL, + "OptionalRelated_String" = NULL, + "OptionalRelated_OptionalNested_Id" = NULL, + "OptionalRelated_OptionalNested_Int" = NULL, + "OptionalRelated_OptionalNested_Ints" = NULL, + "OptionalRelated_OptionalNested_Name" = NULL, + "OptionalRelated_OptionalNested_String" = NULL, + "OptionalRelated_RequiredNested_Id" = NULL, + "OptionalRelated_RequiredNested_Int" = NULL, + "OptionalRelated_RequiredNested_Ints" = NULL, + "OptionalRelated_RequiredNested_Name" = NULL, + "OptionalRelated_RequiredNested_String" = NULL +"""); + } + + #endregion Update association + + #region Update collection + + public override async Task Update_collection_to_parameter() + { + await base.Update_collection_to_parameter(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_nested_collection_to_parameter() + { + await base.Update_nested_collection_to_parameter(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_nested_collection_to_inline_with_lambda() + { + await base.Update_nested_collection_to_inline_with_lambda(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_nested_collection_to_another_nested_collection() + { + await base.Update_nested_collection_to_another_nested_collection(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_collection_referencing_the_original_collection() + { + await base.Update_collection_referencing_the_original_collection(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_inside_structural_collection() + { + await base.Update_inside_structural_collection(); + + AssertExecuteUpdateSql(); + } + + #endregion Update collection + + #region Update primitive collection + + public override async Task Update_primitive_collection_to_constant() + { + await base.Update_primitive_collection_to_constant(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_Ints" = ARRAY[1,2,4]::integer[] +"""); + } + + public override async Task Update_primitive_collection_to_parameter() + { + await base.Update_primitive_collection_to_parameter(); + + AssertExecuteUpdateSql( + """ +@ints='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated_Ints" = @ints +"""); + } + + public override async Task Update_primitive_collection_to_another_collection() + { + await base.Update_primitive_collection_to_another_collection(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated_OptionalNested_Ints" = r."RequiredRelated_RequiredNested_Ints" +"""); + } + + public override async Task Update_inside_primitive_collection() + { + await base.Update_inside_primitive_collection(); + + AssertExecuteUpdateSql(); + } + + #endregion Update primitive collection + + #region Multiple updates + + public override async Task Update_multiple_properties_inside_same_association() + { + await base.Update_multiple_properties_inside_same_association(); + + AssertExecuteUpdateSql( + """ +@p='?' +@p0='?' (DbType = Int32) + +UPDATE "RootEntity" AS r +SET "RequiredRelated_String" = @p, + "RequiredRelated_Int" = @p0 +"""); + } + + public override async Task Update_multiple_properties_inside_associations_and_on_entity_type() + { + await base.Update_multiple_properties_inside_associations_and_on_entity_type(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "Name" = r."Name" || 'Modified', + "RequiredRelated_String" = r."OptionalRelated_String", + "OptionalRelated_RequiredNested_String" = @p +WHERE r."OptionalRelated_Id" IS NOT NULL +"""); + } + + public override async Task Update_multiple_projected_associations_via_anonymous_type() + { + await base.Update_multiple_projected_associations_via_anonymous_type(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated_String" = r."OptionalRelated_String", + "OptionalRelated_String" = @p +WHERE r."OptionalRelated_Id" IS NOT NULL +"""); + } + + #endregion Multiple updates + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs index 1b16090f1..b7e396df5 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task Where_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r WHERE r."RequiredRelated_Int" = 8 """); @@ -26,7 +26,7 @@ public override async Task Where_optional_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r WHERE r."OptionalRelated_Int" = 8 """); @@ -38,7 +38,7 @@ public override async Task Where_nested_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r WHERE r."RequiredRelated_RequiredNested_Int" = 8 """); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..b865eeeb5 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,85 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.ComplexTableSplitting; + +public class ComplexTableSplittingPrimitiveCollectionNpgsqlTest(ComplexTableSplittingNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : ComplexTableSplittingPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +WHERE cardinality(r."RequiredRelated_Ints") = 3 +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +WHERE r."RequiredRelated_Ints"[1] = 1 +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +WHERE 3 = ANY (r."RequiredRelated_Ints") +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +WHERE 2 = ANY (r."RequiredRelated_Ints") +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +WHERE cardinality(r."RequiredRelated_RequiredNested_Ints") = 3 +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(r1.value), 0)::int + FROM unnest(r."RequiredRelated_Ints") AS r1(value)) +FROM "RootEntity" AS r +WHERE ( + SELECT COALESCE(sum(r0.value), 0)::int + FROM unnest(r."RequiredRelated_Ints") AS r0(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingProjectionNpgsqlTest.cs index 53ba46bfd..16d60b83c 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingProjectionNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task Select_related_collection(QueryTrackingBehavior query AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r ORDER BY r."Id" NULLS FIRST """); @@ -26,7 +26,7 @@ public override async Task Select_nested_collection_on_required_related(QueryTra AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r ORDER BY r."Id" NULLS FIRST """); @@ -38,7 +38,7 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -93,7 +93,7 @@ public override async Task Select_related(QueryTrackingBehavior queryTrackingBeh AssertSql( """ -SELECT r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -104,7 +104,7 @@ public override async Task Select_optional_related(QueryTrackingBehavior queryTr AssertSql( """ -SELECT r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" +SELECT r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -115,7 +115,7 @@ public override async Task Select_required_nested_on_required_related(QueryTrack AssertSql( """ -SELECT r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -126,7 +126,7 @@ public override async Task Select_optional_nested_on_required_related(QueryTrack AssertSql( """ -SELECT r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String" +SELECT r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String" FROM "RootEntity" AS r """); } @@ -137,7 +137,7 @@ public override async Task Select_required_nested_on_optional_related(QueryTrack AssertSql( """ -SELECT r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" +SELECT r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -148,7 +148,7 @@ public override async Task Select_optional_nested_on_optional_related(QueryTrack AssertSql( """ -SELECT r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String" +SELECT r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String" FROM "RootEntity" AS r """); } @@ -159,7 +159,7 @@ public override async Task Select_required_related_via_optional_navigation(Query AssertSql( """ -SELECT r0."RequiredRelated_Id", r0."RequiredRelated_Int", r0."RequiredRelated_Name", r0."RequiredRelated_String", r0."RequiredRelated_OptionalNested_Id", r0."RequiredRelated_OptionalNested_Int", r0."RequiredRelated_OptionalNested_Name", r0."RequiredRelated_OptionalNested_String", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" +SELECT r0."RequiredRelated_Id", r0."RequiredRelated_Int", r0."RequiredRelated_Ints", r0."RequiredRelated_Name", r0."RequiredRelated_String", r0."RequiredRelated_OptionalNested_Id", r0."RequiredRelated_OptionalNested_Int", r0."RequiredRelated_OptionalNested_Ints", r0."RequiredRelated_OptionalNested_Name", r0."RequiredRelated_OptionalNested_String", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Ints", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" FROM "RootReferencingEntity" AS r LEFT JOIN "RootEntity" AS r0 ON r."RootEntityId" = r0."Id" """); @@ -171,7 +171,7 @@ public override async Task Select_nested_collection_on_optional_related(QueryTra AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r ORDER BY r."Id" NULLS FIRST """); @@ -204,7 +204,7 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -215,10 +215,10 @@ public override async Task Select_subquery_required_related_FirstOrDefault(Query AssertSql( """ -SELECT r1."RequiredRelated_RequiredNested_Id", r1."RequiredRelated_RequiredNested_Int", r1."RequiredRelated_RequiredNested_Name", r1."RequiredRelated_RequiredNested_String" +SELECT r1."RequiredRelated_RequiredNested_Id", r1."RequiredRelated_RequiredNested_Int", r1."RequiredRelated_RequiredNested_Ints", r1."RequiredRelated_RequiredNested_Name", r1."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" + SELECT r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Ints", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r0 ORDER BY r0."Id" NULLS FIRST LIMIT 1 @@ -232,10 +232,10 @@ public override async Task Select_subquery_optional_related_FirstOrDefault(Query AssertSql( """ -SELECT r1."OptionalRelated_RequiredNested_Id", r1."OptionalRelated_RequiredNested_Int", r1."OptionalRelated_RequiredNested_Name", r1."OptionalRelated_RequiredNested_String" +SELECT r1."OptionalRelated_RequiredNested_Id", r1."OptionalRelated_RequiredNested_Int", r1."OptionalRelated_RequiredNested_Ints", r1."OptionalRelated_RequiredNested_Name", r1."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r0."OptionalRelated_RequiredNested_Id", r0."OptionalRelated_RequiredNested_Int", r0."OptionalRelated_RequiredNested_Name", r0."OptionalRelated_RequiredNested_String" + SELECT r0."OptionalRelated_RequiredNested_Id", r0."OptionalRelated_RequiredNested_Int", r0."OptionalRelated_RequiredNested_Ints", r0."OptionalRelated_RequiredNested_Name", r0."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r0 ORDER BY r0."Id" NULLS FIRST LIMIT 1 diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs index ffd2e23b5..599d6eddc 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs @@ -14,9 +14,9 @@ public override async Task Two_related() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."RequiredRelated_Id" = r."OptionalRelated_Id" AND r."RequiredRelated_Int" = r."OptionalRelated_Int" AND r."RequiredRelated_Name" = r."OptionalRelated_Name" AND r."RequiredRelated_String" = r."OptionalRelated_String" AND (r."RequiredRelated_OptionalNested_Id" = r."RequiredRelated_OptionalNested_Id" OR r."RequiredRelated_OptionalNested_Id" IS NULL) AND (r."RequiredRelated_OptionalNested_Int" = r."RequiredRelated_OptionalNested_Int" OR r."RequiredRelated_OptionalNested_Int" IS NULL) AND (r."RequiredRelated_OptionalNested_Name" = r."RequiredRelated_OptionalNested_Name" OR r."RequiredRelated_OptionalNested_Name" IS NULL) AND (r."RequiredRelated_OptionalNested_String" = r."RequiredRelated_OptionalNested_String" OR r."RequiredRelated_OptionalNested_String" IS NULL) AND r."RequiredRelated_RequiredNested_Id" = r."RequiredRelated_RequiredNested_Id" AND r."RequiredRelated_RequiredNested_Int" = r."RequiredRelated_RequiredNested_Int" AND r."RequiredRelated_RequiredNested_Name" = r."RequiredRelated_RequiredNested_Name" AND r."RequiredRelated_RequiredNested_String" = r."RequiredRelated_RequiredNested_String" +WHERE r."RequiredRelated_Id" = r."OptionalRelated_Id" AND r."RequiredRelated_Int" = r."OptionalRelated_Int" AND r."RequiredRelated_Ints" = r."OptionalRelated_Ints" AND r."RequiredRelated_Name" = r."OptionalRelated_Name" AND r."RequiredRelated_String" = r."OptionalRelated_String" AND (r."RequiredRelated_OptionalNested_Id" = r."RequiredRelated_OptionalNested_Id" OR r."RequiredRelated_OptionalNested_Id" IS NULL) AND (r."RequiredRelated_OptionalNested_Int" = r."RequiredRelated_OptionalNested_Int" OR r."RequiredRelated_OptionalNested_Int" IS NULL) AND (r."RequiredRelated_OptionalNested_Ints" = r."RequiredRelated_OptionalNested_Ints" OR r."RequiredRelated_OptionalNested_Ints" IS NULL) AND (r."RequiredRelated_OptionalNested_Name" = r."RequiredRelated_OptionalNested_Name" OR r."RequiredRelated_OptionalNested_Name" IS NULL) AND (r."RequiredRelated_OptionalNested_String" = r."RequiredRelated_OptionalNested_String" OR r."RequiredRelated_OptionalNested_String" IS NULL) AND r."RequiredRelated_RequiredNested_Id" = r."RequiredRelated_RequiredNested_Id" AND r."RequiredRelated_RequiredNested_Int" = r."RequiredRelated_RequiredNested_Int" AND r."RequiredRelated_RequiredNested_Ints" = r."RequiredRelated_RequiredNested_Ints" AND r."RequiredRelated_RequiredNested_Name" = r."RequiredRelated_RequiredNested_Name" AND r."RequiredRelated_RequiredNested_String" = r."RequiredRelated_RequiredNested_String" """); } @@ -26,9 +26,9 @@ public override async Task Two_nested() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."RequiredRelated_RequiredNested_Id" = r."OptionalRelated_RequiredNested_Id" AND r."RequiredRelated_RequiredNested_Int" = r."OptionalRelated_RequiredNested_Int" AND r."RequiredRelated_RequiredNested_Name" = r."OptionalRelated_RequiredNested_Name" AND r."RequiredRelated_RequiredNested_String" = r."OptionalRelated_RequiredNested_String" +WHERE r."RequiredRelated_RequiredNested_Id" = r."OptionalRelated_RequiredNested_Id" AND r."RequiredRelated_RequiredNested_Int" = r."OptionalRelated_RequiredNested_Int" AND r."RequiredRelated_RequiredNested_Ints" = r."OptionalRelated_RequiredNested_Ints" AND r."RequiredRelated_RequiredNested_Name" = r."OptionalRelated_RequiredNested_Name" AND r."RequiredRelated_RequiredNested_String" = r."OptionalRelated_RequiredNested_String" """); } @@ -38,9 +38,9 @@ public override async Task Not_equals() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."RequiredRelated_Id" <> r."OptionalRelated_Id" OR r."OptionalRelated_Id" IS NULL OR r."RequiredRelated_Int" <> r."OptionalRelated_Int" OR r."OptionalRelated_Int" IS NULL OR r."RequiredRelated_Name" <> r."OptionalRelated_Name" OR r."OptionalRelated_Name" IS NULL OR r."RequiredRelated_String" <> r."OptionalRelated_String" OR r."OptionalRelated_String" IS NULL OR ((r."RequiredRelated_OptionalNested_Id" <> r."RequiredRelated_OptionalNested_Id" OR r."RequiredRelated_OptionalNested_Id" IS NULL) AND r."RequiredRelated_OptionalNested_Id" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_Int" <> r."RequiredRelated_OptionalNested_Int" OR r."RequiredRelated_OptionalNested_Int" IS NULL) AND r."RequiredRelated_OptionalNested_Int" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_Name" <> r."RequiredRelated_OptionalNested_Name" OR r."RequiredRelated_OptionalNested_Name" IS NULL) AND r."RequiredRelated_OptionalNested_Name" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_String" <> r."RequiredRelated_OptionalNested_String" OR r."RequiredRelated_OptionalNested_String" IS NULL) AND r."RequiredRelated_OptionalNested_String" IS NOT NULL) OR r."RequiredRelated_RequiredNested_Id" <> r."RequiredRelated_RequiredNested_Id" OR r."RequiredRelated_RequiredNested_Id" IS NULL OR r."RequiredRelated_RequiredNested_Int" <> r."RequiredRelated_RequiredNested_Int" OR r."RequiredRelated_RequiredNested_Int" IS NULL OR r."RequiredRelated_RequiredNested_Name" <> r."RequiredRelated_RequiredNested_Name" OR r."RequiredRelated_RequiredNested_Name" IS NULL OR r."RequiredRelated_RequiredNested_String" <> r."RequiredRelated_RequiredNested_String" OR r."RequiredRelated_RequiredNested_String" IS NULL +WHERE r."RequiredRelated_Id" <> r."OptionalRelated_Id" OR r."OptionalRelated_Id" IS NULL OR r."RequiredRelated_Int" <> r."OptionalRelated_Int" OR r."OptionalRelated_Int" IS NULL OR r."RequiredRelated_Ints" <> r."OptionalRelated_Ints" OR r."OptionalRelated_Ints" IS NULL OR r."RequiredRelated_Name" <> r."OptionalRelated_Name" OR r."OptionalRelated_Name" IS NULL OR r."RequiredRelated_String" <> r."OptionalRelated_String" OR r."OptionalRelated_String" IS NULL OR ((r."RequiredRelated_OptionalNested_Id" <> r."RequiredRelated_OptionalNested_Id" OR r."RequiredRelated_OptionalNested_Id" IS NULL) AND r."RequiredRelated_OptionalNested_Id" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_Int" <> r."RequiredRelated_OptionalNested_Int" OR r."RequiredRelated_OptionalNested_Int" IS NULL) AND r."RequiredRelated_OptionalNested_Int" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_Ints" <> r."RequiredRelated_OptionalNested_Ints" OR r."RequiredRelated_OptionalNested_Ints" IS NULL) AND r."RequiredRelated_OptionalNested_Ints" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_Name" <> r."RequiredRelated_OptionalNested_Name" OR r."RequiredRelated_OptionalNested_Name" IS NULL) AND r."RequiredRelated_OptionalNested_Name" IS NOT NULL) OR ((r."RequiredRelated_OptionalNested_String" <> r."RequiredRelated_OptionalNested_String" OR r."RequiredRelated_OptionalNested_String" IS NULL) AND r."RequiredRelated_OptionalNested_String" IS NOT NULL) OR r."RequiredRelated_RequiredNested_Id" <> r."RequiredRelated_RequiredNested_Id" OR r."RequiredRelated_RequiredNested_Id" IS NULL OR r."RequiredRelated_RequiredNested_Int" <> r."RequiredRelated_RequiredNested_Int" OR r."RequiredRelated_RequiredNested_Int" IS NULL OR r."RequiredRelated_RequiredNested_Ints" <> r."RequiredRelated_RequiredNested_Ints" OR r."RequiredRelated_RequiredNested_Ints" IS NULL OR r."RequiredRelated_RequiredNested_Name" <> r."RequiredRelated_RequiredNested_Name" OR r."RequiredRelated_RequiredNested_Name" IS NULL OR r."RequiredRelated_RequiredNested_String" <> r."RequiredRelated_RequiredNested_String" OR r."RequiredRelated_RequiredNested_String" IS NULL """); } @@ -50,7 +50,7 @@ public override async Task Related_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r WHERE r."OptionalRelated_Id" IS NULL """); @@ -62,9 +62,9 @@ public override async Task Related_with_parameter_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."OptionalRelated_Id" IS NULL AND r."OptionalRelated_Int" IS NULL AND r."OptionalRelated_Name" IS NULL AND r."OptionalRelated_String" IS NULL AND r."OptionalRelated_OptionalNested_Id" IS NULL AND r."OptionalRelated_OptionalNested_Int" IS NULL AND r."OptionalRelated_OptionalNested_Name" IS NULL AND r."OptionalRelated_OptionalNested_String" IS NULL AND r."OptionalRelated_RequiredNested_Id" IS NULL AND r."OptionalRelated_RequiredNested_Int" IS NULL AND r."OptionalRelated_RequiredNested_Name" IS NULL AND r."OptionalRelated_RequiredNested_String" IS NULL +WHERE r."OptionalRelated_Id" IS NULL AND r."OptionalRelated_Int" IS NULL AND r."OptionalRelated_Ints" IS NULL AND r."OptionalRelated_Name" IS NULL AND r."OptionalRelated_String" IS NULL AND r."OptionalRelated_OptionalNested_Id" IS NULL AND r."OptionalRelated_OptionalNested_Int" IS NULL AND r."OptionalRelated_OptionalNested_Ints" IS NULL AND r."OptionalRelated_OptionalNested_Name" IS NULL AND r."OptionalRelated_OptionalNested_String" IS NULL AND r."OptionalRelated_RequiredNested_Id" IS NULL AND r."OptionalRelated_RequiredNested_Int" IS NULL AND r."OptionalRelated_RequiredNested_Ints" IS NULL AND r."OptionalRelated_RequiredNested_Name" IS NULL AND r."OptionalRelated_RequiredNested_String" IS NULL """); } @@ -74,7 +74,7 @@ public override async Task Nested_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r WHERE r."RequiredRelated_OptionalNested_Id" IS NULL """); @@ -86,9 +86,9 @@ public override async Task Nested_with_inline() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."RequiredRelated_RequiredNested_Id" = 1000 AND r."RequiredRelated_RequiredNested_Int" = 8 AND r."RequiredRelated_RequiredNested_Name" = 'Root1_RequiredRelated_RequiredNested' AND r."RequiredRelated_RequiredNested_String" = 'foo' +WHERE r."RequiredRelated_RequiredNested_Id" = 1000 AND r."RequiredRelated_RequiredNested_Int" = 8 AND r."RequiredRelated_RequiredNested_Ints" = ARRAY[1,2,3]::integer[] AND r."RequiredRelated_RequiredNested_Name" = 'Root1_RequiredRelated_RequiredNested' AND r."RequiredRelated_RequiredNested_String" = 'foo' """); } @@ -100,12 +100,13 @@ public override async Task Nested_with_parameter() """ @entity_equality_nested_Id='?' (DbType = Int32) @entity_equality_nested_Int='?' (DbType = Int32) +@entity_equality_nested_Ints='?' (DbType = Object) @entity_equality_nested_Name='?' @entity_equality_nested_String='?' -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r -WHERE r."RequiredRelated_RequiredNested_Id" = @entity_equality_nested_Id AND r."RequiredRelated_RequiredNested_Int" = @entity_equality_nested_Int AND r."RequiredRelated_RequiredNested_Name" = @entity_equality_nested_Name AND r."RequiredRelated_RequiredNested_String" = @entity_equality_nested_String +WHERE r."RequiredRelated_RequiredNested_Id" = @entity_equality_nested_Id AND r."RequiredRelated_RequiredNested_Int" = @entity_equality_nested_Int AND r."RequiredRelated_RequiredNested_Ints" = @entity_equality_nested_Ints AND r."RequiredRelated_RequiredNested_Name" = @entity_equality_nested_Name AND r."RequiredRelated_RequiredNested_String" = @entity_equality_nested_String """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs index d14120d3c..56c6c8a93 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs @@ -12,7 +12,7 @@ public override async Task Count() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" @@ -22,7 +22,7 @@ public override async Task Count() INNER JOIN "NestedType" AS n2 ON r2."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n4 ON r3."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r3."RequiredNestedId" = n5."Id" @@ -43,7 +43,7 @@ public override async Task Where() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" @@ -53,7 +53,7 @@ public override async Task Where() INNER JOIN "NestedType" AS n2 ON r2."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n4 ON r3."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r3."RequiredNestedId" = n5."Id" @@ -74,7 +74,7 @@ public override async Task OrderBy_ElementAt() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" @@ -84,7 +84,7 @@ public override async Task OrderBy_ElementAt() INNER JOIN "NestedType" AS n2 ON r2."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n4 ON r3."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r3."RequiredNestedId" = n5."Id" @@ -109,7 +109,7 @@ public override async Task Distinct() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n."Id", n0."Id", r3."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n."Id", n0."Id", r3."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r2 ON r."OptionalRelatedId" = r2."Id" LEFT JOIN "NestedType" AS n ON r2."OptionalNestedId" = n."Id" @@ -119,7 +119,7 @@ public override async Task Distinct() INNER JOIN "NestedType" AS n2 ON r3."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r2."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r4."Id", r4."CollectionRootId", r4."Int", r4."Name", r4."OptionalNestedId", r4."RequiredNestedId", r4."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r4."Id", r4."CollectionRootId", r4."Int", r4."Ints", r4."Name", r4."OptionalNestedId", r4."RequiredNestedId", r4."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r4 LEFT JOIN "NestedType" AS n4 ON r4."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r4."RequiredNestedId" = n5."Id" @@ -129,7 +129,7 @@ LEFT JOIN ( WHERE ( SELECT count(*)::int FROM ( - SELECT DISTINCT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String" + SELECT DISTINCT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String" FROM "RelatedType" AS r0 WHERE r."Id" = r0."CollectionRootId" ) AS r1) = 2 @@ -143,12 +143,12 @@ public override async Task Distinct_projected(QueryTrackingBehavior queryTrackin AssertSql( """ -SELECT r."Id", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2" +SELECT r."Id", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id" AS "Id0", n0."Id" AS "Id1", n1."Id" AS "Id2", n1."CollectionRelatedId", n1."Int" AS "Int0", n1."Name" AS "Name0", n1."String" AS "String0", n."CollectionRelatedId" AS "CollectionRelatedId0", n."Int" AS "Int1", n."Name" AS "Name1", n."String" AS "String1", n0."CollectionRelatedId" AS "CollectionRelatedId1", n0."Int" AS "Int2", n0."Name" AS "Name2", n0."String" AS "String2" + SELECT r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id" AS "Id0", n0."Id" AS "Id1", n1."Id" AS "Id2", n1."CollectionRelatedId", n1."Int" AS "Int0", n1."Ints" AS "Ints0", n1."Name" AS "Name0", n1."String" AS "String0", n."CollectionRelatedId" AS "CollectionRelatedId0", n."Int" AS "Int1", n."Ints" AS "Ints1", n."Name" AS "Name1", n."String" AS "String1", n0."CollectionRelatedId" AS "CollectionRelatedId1", n0."Int" AS "Int2", n0."Ints" AS "Ints2", n0."Name" AS "Name2", n0."String" AS "String2" FROM ( - SELECT DISTINCT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String" + SELECT DISTINCT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String" FROM "RelatedType" AS r0 WHERE r."Id" = r0."CollectionRootId" ) AS r1 @@ -217,7 +217,7 @@ public override async Task GroupBy() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" @@ -227,7 +227,7 @@ public override async Task GroupBy() INNER JOIN "NestedType" AS n2 ON r2."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n4 ON r3."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r3."RequiredNestedId" = n5."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsIncludeNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsIncludeNpgsqlTest.cs index b53f940db..e0af4c313 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsIncludeNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsIncludeNpgsqlTest.cs @@ -12,7 +12,7 @@ public override async Task Include_required(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -22,7 +22,7 @@ public override async Task Include_required(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -39,7 +39,7 @@ public override async Task Include_optional(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -49,7 +49,7 @@ public override async Task Include_optional(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -66,7 +66,7 @@ public override async Task Include_collection(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -76,7 +76,7 @@ public override async Task Include_collection(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -93,7 +93,7 @@ public override async Task Include_required_optional_and_collection(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -103,7 +103,7 @@ public override async Task Include_required_optional_and_collection(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -120,7 +120,7 @@ public override async Task Include_nested(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -130,7 +130,7 @@ public override async Task Include_nested(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -147,7 +147,7 @@ public override async Task Include_nested_optional(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -157,7 +157,7 @@ public override async Task Include_nested_optional(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -174,7 +174,7 @@ public override async Task Include_nested_collection(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -184,7 +184,7 @@ public override async Task Include_nested_collection(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -201,7 +201,7 @@ public override async Task Include_nested_collection_on_optional(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -211,7 +211,7 @@ public override async Task Include_nested_collection_on_optional(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -228,7 +228,7 @@ public override async Task Include_nested_collection_on_collection(bool async) AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -238,7 +238,7 @@ public override async Task Include_nested_collection_on_collection(bool async) INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs index bed384805..07d196ff0 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs @@ -16,7 +16,7 @@ public override async Task Where_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -26,7 +26,7 @@ public override async Task Where_related_property() INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -44,7 +44,7 @@ public override async Task Where_optional_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -54,7 +54,7 @@ public override async Task Where_optional_related_property() INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -72,7 +72,7 @@ public override async Task Where_nested_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -82,7 +82,7 @@ public override async Task Where_nested_related_property() LEFT JOIN "NestedType" AS n2 ON r0."OptionalNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..da2bbf9b2 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,166 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.Navigations; + +public class NavigationsPrimitiveCollectionNpgsqlTest(NavigationsNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : NavigationsPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" +LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" +LEFT JOIN "NestedType" AS n0 ON r1."RequiredNestedId" = n0."Id" +LEFT JOIN "NestedType" AS n1 ON r0."OptionalNestedId" = n1."Id" +INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" +LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" +LEFT JOIN ( + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" + FROM "RelatedType" AS r2 + LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" + INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" + LEFT JOIN "NestedType" AS n6 ON r2."Id" = n6."CollectionRelatedId" +) AS s ON r."Id" = s."CollectionRootId" +LEFT JOIN "NestedType" AS n7 ON r0."Id" = n7."CollectionRelatedId" +WHERE cardinality(r0."Ints") = 3 +ORDER BY r."Id" NULLS FIRST, r0."Id" NULLS FIRST, r1."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, n3."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" +LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" +LEFT JOIN "NestedType" AS n0 ON r1."RequiredNestedId" = n0."Id" +LEFT JOIN "NestedType" AS n1 ON r0."OptionalNestedId" = n1."Id" +INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" +LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" +LEFT JOIN ( + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" + FROM "RelatedType" AS r2 + LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" + INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" + LEFT JOIN "NestedType" AS n6 ON r2."Id" = n6."CollectionRelatedId" +) AS s ON r."Id" = s."CollectionRootId" +LEFT JOIN "NestedType" AS n7 ON r0."Id" = n7."CollectionRelatedId" +WHERE r0."Ints"[1] = 1 +ORDER BY r."Id" NULLS FIRST, r0."Id" NULLS FIRST, r1."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, n3."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" +LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" +LEFT JOIN "NestedType" AS n0 ON r1."RequiredNestedId" = n0."Id" +LEFT JOIN "NestedType" AS n1 ON r0."OptionalNestedId" = n1."Id" +INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" +LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" +LEFT JOIN ( + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" + FROM "RelatedType" AS r2 + LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" + INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" + LEFT JOIN "NestedType" AS n6 ON r2."Id" = n6."CollectionRelatedId" +) AS s ON r."Id" = s."CollectionRootId" +LEFT JOIN "NestedType" AS n7 ON r0."Id" = n7."CollectionRelatedId" +WHERE 3 = ANY (r0."Ints") +ORDER BY r."Id" NULLS FIRST, r0."Id" NULLS FIRST, r1."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, n3."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" +LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" +LEFT JOIN "NestedType" AS n0 ON r1."RequiredNestedId" = n0."Id" +LEFT JOIN "NestedType" AS n1 ON r0."OptionalNestedId" = n1."Id" +INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" +LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" +LEFT JOIN ( + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" + FROM "RelatedType" AS r2 + LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" + INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" + LEFT JOIN "NestedType" AS n6 ON r2."Id" = n6."CollectionRelatedId" +) AS s ON r."Id" = s."CollectionRootId" +LEFT JOIN "NestedType" AS n7 ON r0."Id" = n7."CollectionRelatedId" +WHERE 2 = ANY (r0."Ints") +ORDER BY r."Id" NULLS FIRST, r0."Id" NULLS FIRST, r1."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, n3."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" +LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" +LEFT JOIN "NestedType" AS n0 ON r1."OptionalNestedId" = n0."Id" +LEFT JOIN "NestedType" AS n1 ON r1."RequiredNestedId" = n1."Id" +LEFT JOIN "NestedType" AS n2 ON r0."OptionalNestedId" = n2."Id" +LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" +LEFT JOIN ( + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" + FROM "RelatedType" AS r2 + LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" + INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" + LEFT JOIN "NestedType" AS n6 ON r2."Id" = n6."CollectionRelatedId" +) AS s ON r."Id" = s."CollectionRootId" +LEFT JOIN "NestedType" AS n7 ON r0."Id" = n7."CollectionRelatedId" +WHERE cardinality(n."Ints") = 3 +ORDER BY r."Id" NULLS FIRST, r0."Id" NULLS FIRST, n."Id" NULLS FIRST, r1."Id" NULLS FIRST, n0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, n3."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(i0.value), 0)::int + FROM unnest(r0."Ints") AS i0(value)) +FROM "RootEntity" AS r +INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" +WHERE ( + SELECT COALESCE(sum(i.value), 0)::int + FROM unnest(r0."Ints") AS i(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsProjectionNpgsqlTest.cs index 81bc25fd2..9599d5148 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsProjectionNpgsqlTest.cs @@ -12,7 +12,7 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -22,7 +22,7 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -93,7 +93,7 @@ public override async Task Select_related(QueryTrackingBehavior queryTrackingBeh AssertSql( """ -SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String" +SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -109,7 +109,7 @@ public override async Task Select_optional_related(QueryTrackingBehavior queryTr AssertSql( """ -SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String" +SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -125,7 +125,7 @@ public override async Task Select_required_nested_on_required_related(QueryTrack AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -138,7 +138,7 @@ public override async Task Select_optional_nested_on_required_related(QueryTrack AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -151,7 +151,7 @@ public override async Task Select_required_nested_on_optional_related(QueryTrack AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -164,7 +164,7 @@ public override async Task Select_optional_nested_on_optional_related(QueryTrack AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -177,7 +177,7 @@ public override async Task Select_required_related_via_optional_navigation(Query AssertSql( """ -SELECT r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r."Id", r0."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String" +SELECT r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r."Id", r0."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String" FROM "RootReferencingEntity" AS r LEFT JOIN "RootEntity" AS r0 ON r."RootEntityId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r0."RequiredRelatedId" = r1."Id" @@ -198,10 +198,10 @@ public override async Task Select_related_collection(QueryTrackingBehavior query AssertSql( """ -SELECT r."Id", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2" +SELECT r."Id", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2" FROM "RootEntity" AS r LEFT JOIN ( - SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id" AS "Id0", n0."Id" AS "Id1", n1."Id" AS "Id2", n1."CollectionRelatedId", n1."Int" AS "Int0", n1."Name" AS "Name0", n1."String" AS "String0", n."CollectionRelatedId" AS "CollectionRelatedId0", n."Int" AS "Int1", n."Name" AS "Name1", n."String" AS "String1", n0."CollectionRelatedId" AS "CollectionRelatedId1", n0."Int" AS "Int2", n0."Name" AS "Name2", n0."String" AS "String2" + SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id" AS "Id0", n0."Id" AS "Id1", n1."Id" AS "Id2", n1."CollectionRelatedId", n1."Int" AS "Int0", n1."Ints" AS "Ints0", n1."Name" AS "Name0", n1."String" AS "String0", n."CollectionRelatedId" AS "CollectionRelatedId0", n."Int" AS "Int1", n."Ints" AS "Ints1", n."Name" AS "Name1", n."String" AS "String1", n0."CollectionRelatedId" AS "CollectionRelatedId1", n0."Int" AS "Int2", n0."Ints" AS "Ints2", n0."Name" AS "Name2", n0."String" AS "String2" FROM "RelatedType" AS r0 LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" INNER JOIN "NestedType" AS n0 ON r0."RequiredNestedId" = n0."Id" @@ -217,7 +217,7 @@ public override async Task Select_nested_collection_on_required_related(QueryTra AssertSql( """ -SELECT r."Id", r0."Id", n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r0."Id", n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."Id" = n."CollectionRelatedId" @@ -231,7 +231,7 @@ public override async Task Select_nested_collection_on_optional_related(QueryTra AssertSql( """ -SELECT r."Id", r0."Id", n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r0."Id", n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."Id" = n."CollectionRelatedId" @@ -245,7 +245,7 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q AssertSql( """ -SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String" +SELECT r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", r."Id", n."Id", n0."Id", n1."Id", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."Id" = r0."CollectionRootId" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -261,7 +261,7 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."Id" = n."CollectionRelatedId" @@ -274,7 +274,7 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer AssertSql( """ -SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."Id" = n."CollectionRelatedId" @@ -291,7 +291,7 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Name", n8."String", s0."Id", s0."CollectionRootId", s0."Int", s0."Name", s0."OptionalNestedId", s0."RequiredNestedId", s0."String", s0."Id0", s0."Id1", s0."Id2", s0."CollectionRelatedId", s0."Int0", s0."Name0", s0."String0", s0."CollectionRelatedId0", s0."Int1", s0."Name1", s0."String1", s0."CollectionRelatedId1", s0."Int2", s0."Name2", s0."String2", n12."Id", n12."CollectionRelatedId", n12."Int", n12."Name", n12."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Ints", n8."Name", n8."String", s0."Id", s0."CollectionRootId", s0."Int", s0."Ints", s0."Name", s0."OptionalNestedId", s0."RequiredNestedId", s0."String", s0."Id0", s0."Id1", s0."Id2", s0."CollectionRelatedId", s0."Int0", s0."Ints0", s0."Name0", s0."String0", s0."CollectionRelatedId0", s0."Int1", s0."Ints1", s0."Name1", s0."String1", s0."CollectionRelatedId1", s0."Int2", s0."Ints2", s0."Name2", s0."String2", n12."Id", n12."CollectionRelatedId", n12."Int", n12."Ints", n12."Name", n12."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -301,7 +301,7 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -310,7 +310,7 @@ LEFT JOIN ( LEFT JOIN "NestedType" AS n7 ON r1."Id" = n7."CollectionRelatedId" LEFT JOIN "NestedType" AS n8 ON r0."Id" = n8."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n9."Id" AS "Id0", n10."Id" AS "Id1", n11."Id" AS "Id2", n11."CollectionRelatedId", n11."Int" AS "Int0", n11."Name" AS "Name0", n11."String" AS "String0", n9."CollectionRelatedId" AS "CollectionRelatedId0", n9."Int" AS "Int1", n9."Name" AS "Name1", n9."String" AS "String1", n10."CollectionRelatedId" AS "CollectionRelatedId1", n10."Int" AS "Int2", n10."Name" AS "Name2", n10."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n9."Id" AS "Id0", n10."Id" AS "Id1", n11."Id" AS "Id2", n11."CollectionRelatedId", n11."Int" AS "Int0", n11."Ints" AS "Ints0", n11."Name" AS "Name0", n11."String" AS "String0", n9."CollectionRelatedId" AS "CollectionRelatedId0", n9."Int" AS "Int1", n9."Ints" AS "Ints1", n9."Name" AS "Name1", n9."String" AS "String1", n10."CollectionRelatedId" AS "CollectionRelatedId1", n10."Int" AS "Int2", n10."Ints" AS "Ints2", n10."Name" AS "Name2", n10."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n9 ON r3."OptionalNestedId" = n9."Id" INNER JOIN "NestedType" AS n10 ON r3."RequiredNestedId" = n10."Id" @@ -331,10 +331,10 @@ public override async Task Select_subquery_required_related_FirstOrDefault(Query AssertSql( """ -SELECT s."Id", s."CollectionRelatedId", s."Int", s."Name", s."String" +SELECT s."Id", s."CollectionRelatedId", s."Int", s."Ints", s."Name", s."String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" + SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r0 INNER JOIN "RelatedType" AS r1 ON r0."RequiredRelatedId" = r1."Id" INNER JOIN "NestedType" AS n ON r1."RequiredNestedId" = n."Id" @@ -350,10 +350,10 @@ public override async Task Select_subquery_optional_related_FirstOrDefault(Query AssertSql( """ -SELECT s."Id", s."CollectionRelatedId", s."Int", s."Name", s."String" +SELECT s."Id", s."CollectionRelatedId", s."Int", s."Ints", s."Name", s."String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT n."Id", n."CollectionRelatedId", n."Int", n."Name", n."String" + SELECT n."Id", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r0 LEFT JOIN "RelatedType" AS r1 ON r0."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."RequiredNestedId" = n."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsSetOperationsNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsSetOperationsNpgsqlTest.cs index 03c98ac14..f9be05387 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsSetOperationsNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsSetOperationsNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task On_related() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n."Id", n0."Id", r3."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n."Id", n0."Id", r3."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r2 ON r."OptionalRelatedId" = r2."Id" LEFT JOIN "NestedType" AS n ON r2."OptionalNestedId" = n."Id" @@ -24,7 +24,7 @@ public override async Task On_related() INNER JOIN "NestedType" AS n2 ON r3."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r2."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r4."Id", r4."CollectionRootId", r4."Int", r4."Name", r4."OptionalNestedId", r4."RequiredNestedId", r4."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r4."Id", r4."CollectionRootId", r4."Int", r4."Ints", r4."Name", r4."OptionalNestedId", r4."RequiredNestedId", r4."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r4 LEFT JOIN "NestedType" AS n4 ON r4."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r4."RequiredNestedId" = n5."Id" @@ -83,7 +83,7 @@ public override async Task On_nested() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n5."Id", n5."CollectionRelatedId", n5."Int", n5."Name", n5."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n9."Id", n9."CollectionRelatedId", n9."Int", n9."Name", n9."String", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n4."CollectionRelatedId", n4."Int", n4."Name", n4."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n5."Id", n5."CollectionRelatedId", n5."Int", n5."Ints", n5."Name", n5."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n9."Id", n9."CollectionRelatedId", n9."Int", n9."Ints", n9."Name", n9."String", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n4."CollectionRelatedId", n4."Int", n4."Ints", n4."Name", n4."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -93,7 +93,7 @@ public override async Task On_nested() INNER JOIN "NestedType" AS n4 ON r0."RequiredNestedId" = n4."Id" LEFT JOIN "NestedType" AS n5 ON r1."Id" = n5."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n6."Id" AS "Id0", n7."Id" AS "Id1", n8."Id" AS "Id2", n8."CollectionRelatedId", n8."Int" AS "Int0", n8."Name" AS "Name0", n8."String" AS "String0", n6."CollectionRelatedId" AS "CollectionRelatedId0", n6."Int" AS "Int1", n6."Name" AS "Name1", n6."String" AS "String1", n7."CollectionRelatedId" AS "CollectionRelatedId1", n7."Int" AS "Int2", n7."Name" AS "Name2", n7."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n6."Id" AS "Id0", n7."Id" AS "Id1", n8."Id" AS "Id2", n8."CollectionRelatedId", n8."Int" AS "Int0", n8."Ints" AS "Ints0", n8."Name" AS "Name0", n8."String" AS "String0", n6."CollectionRelatedId" AS "CollectionRelatedId0", n6."Int" AS "Int1", n6."Ints" AS "Ints1", n6."Name" AS "Name1", n6."String" AS "String1", n7."CollectionRelatedId" AS "CollectionRelatedId1", n7."Int" AS "Int2", n7."Ints" AS "Ints2", n7."Name" AS "Name2", n7."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n6 ON r2."OptionalNestedId" = n6."Id" INNER JOIN "NestedType" AS n7 ON r2."RequiredNestedId" = n7."Id" @@ -121,7 +121,7 @@ public override async Task Over_different_collection_properties() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n5."Id", n5."CollectionRelatedId", n5."Int", n5."Name", n5."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n9."Id", n9."CollectionRelatedId", n9."Int", n9."Name", n9."String", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n4."CollectionRelatedId", n4."Int", n4."Name", n4."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n5."Id", n5."CollectionRelatedId", n5."Int", n5."Ints", n5."Name", n5."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n9."Id", n9."CollectionRelatedId", n9."Int", n9."Ints", n9."Name", n9."String", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n4."CollectionRelatedId", n4."Int", n4."Ints", n4."Name", n4."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -131,7 +131,7 @@ public override async Task Over_different_collection_properties() INNER JOIN "NestedType" AS n4 ON r0."RequiredNestedId" = n4."Id" LEFT JOIN "NestedType" AS n5 ON r1."Id" = n5."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n6."Id" AS "Id0", n7."Id" AS "Id1", n8."Id" AS "Id2", n8."CollectionRelatedId", n8."Int" AS "Int0", n8."Name" AS "Name0", n8."String" AS "String0", n6."CollectionRelatedId" AS "CollectionRelatedId0", n6."Int" AS "Int1", n6."Name" AS "Name1", n6."String" AS "String1", n7."CollectionRelatedId" AS "CollectionRelatedId1", n7."Int" AS "Int2", n7."Name" AS "Name2", n7."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n6."Id" AS "Id0", n7."Id" AS "Id1", n8."Id" AS "Id2", n8."CollectionRelatedId", n8."Int" AS "Int0", n8."Ints" AS "Ints0", n8."Name" AS "Name0", n8."String" AS "String0", n6."CollectionRelatedId" AS "CollectionRelatedId0", n6."Int" AS "Int1", n6."Ints" AS "Ints1", n6."Name" AS "Name1", n6."String" AS "String1", n7."CollectionRelatedId" AS "CollectionRelatedId1", n7."Int" AS "Int2", n7."Ints" AS "Ints2", n7."Name" AS "Name2", n7."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n6 ON r2."OptionalNestedId" = n6."Id" INNER JOIN "NestedType" AS n7 ON r2."RequiredNestedId" = n7."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsStructuralEqualityNpgsqlTest.cs index 401206d4a..415e3616d 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsStructuralEqualityNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task Two_related() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -24,7 +24,7 @@ public override async Task Two_related() INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -42,7 +42,7 @@ public override async Task Two_nested() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -52,7 +52,7 @@ public override async Task Two_nested() LEFT JOIN "NestedType" AS n2 ON r0."OptionalNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -70,7 +70,7 @@ public override async Task Not_equals() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -80,7 +80,7 @@ public override async Task Not_equals() INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -98,7 +98,7 @@ public override async Task Related_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -108,7 +108,7 @@ public override async Task Related_with_inline_null() INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -126,7 +126,7 @@ public override async Task Related_with_parameter_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r0."Id", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n."Id", n0."Id", r1."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r0 ON r."OptionalRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -136,7 +136,7 @@ public override async Task Related_with_parameter_null() INNER JOIN "NestedType" AS n2 ON r1."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r0."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -154,7 +154,7 @@ public override async Task Nested_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "NestedType" AS n ON r0."OptionalNestedId" = n."Id" @@ -164,7 +164,7 @@ public override async Task Nested_with_inline_null() INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -182,7 +182,7 @@ public override async Task Nested_with_inline() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -192,7 +192,7 @@ public override async Task Nested_with_inline() LEFT JOIN "NestedType" AS n2 ON r0."OptionalNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -212,7 +212,7 @@ public override async Task Nested_with_parameter() """ @entity_equality_nested_Id='1000' (Nullable = true) -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Name", n."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" INNER JOIN "NestedType" AS n ON r0."RequiredNestedId" = n."Id" @@ -222,7 +222,7 @@ public override async Task Nested_with_parameter() LEFT JOIN "NestedType" AS n2 ON r0."OptionalNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -240,7 +240,7 @@ public override async Task Two_nested_collections() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n."Id", n0."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -250,7 +250,7 @@ public override async Task Two_nested_collections() INNER JOIN "NestedType" AS n2 ON r0."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n4 ON r2."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r2."RequiredNestedId" = n5."Id" @@ -284,7 +284,7 @@ public override async Task Contains_with_inline() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Ints", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Ints", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -294,7 +294,7 @@ public override async Task Contains_with_inline() INNER JOIN "NestedType" AS n3 ON r0."RequiredNestedId" = n3."Id" LEFT JOIN "NestedType" AS n4 ON r1."Id" = n4."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Name" AS "Name2", n6."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Ints" AS "Ints0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Ints" AS "Ints1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Ints" AS "Ints2", n6."Name" AS "Name2", n6."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n5 ON r2."OptionalNestedId" = n5."Id" INNER JOIN "NestedType" AS n6 ON r2."RequiredNestedId" = n6."Id" @@ -317,7 +317,7 @@ public override async Task Contains_with_parameter() """ @entity_equality_nested_Id='1002' (Nullable = true) -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Ints", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Ints", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -327,7 +327,7 @@ public override async Task Contains_with_parameter() INNER JOIN "NestedType" AS n3 ON r0."RequiredNestedId" = n3."Id" LEFT JOIN "NestedType" AS n4 ON r1."Id" = n4."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Name" AS "Name2", n6."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Ints" AS "Ints0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Ints" AS "Ints1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Ints" AS "Ints2", n6."Name" AS "Name2", n6."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n5 ON r2."OptionalNestedId" = n5."Id" INNER JOIN "NestedType" AS n6 ON r2."RequiredNestedId" = n6."Id" @@ -348,10 +348,10 @@ public override async Task Contains_with_operators_composed_on_the_collection() AssertSql( """ -@get_Item_Int='103' +@get_Item_Int='106' @entity_equality_get_Item_Id='3003' (Nullable = true) -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", r0."Id", n0."Id", n1."Id", n2."Id", n3."Id", n4."Id", n4."CollectionRelatedId", n4."Int", n4."Ints", n4."Name", n4."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r0."CollectionRootId", r0."Int", r0."Ints", r0."Name", r0."OptionalNestedId", r0."RequiredNestedId", r0."String", n8."Id", n8."CollectionRelatedId", n8."Int", n8."Ints", n8."Name", n8."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String" FROM "RootEntity" AS r INNER JOIN "RelatedType" AS r0 ON r."RequiredRelatedId" = r0."Id" LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" @@ -361,7 +361,7 @@ public override async Task Contains_with_operators_composed_on_the_collection() INNER JOIN "NestedType" AS n3 ON r0."RequiredNestedId" = n3."Id" LEFT JOIN "NestedType" AS n4 ON r1."Id" = n4."CollectionRelatedId" LEFT JOIN ( - SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Name" AS "Name2", n6."String" AS "String2" + SELECT r2."Id", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n5."Id" AS "Id0", n6."Id" AS "Id1", n7."Id" AS "Id2", n7."CollectionRelatedId", n7."Int" AS "Int0", n7."Ints" AS "Ints0", n7."Name" AS "Name0", n7."String" AS "String0", n5."CollectionRelatedId" AS "CollectionRelatedId0", n5."Int" AS "Int1", n5."Ints" AS "Ints1", n5."Name" AS "Name1", n5."String" AS "String1", n6."CollectionRelatedId" AS "CollectionRelatedId1", n6."Int" AS "Int2", n6."Ints" AS "Ints2", n6."Name" AS "Name2", n6."String" AS "String2" FROM "RelatedType" AS r2 LEFT JOIN "NestedType" AS n5 ON r2."OptionalNestedId" = n5."Id" INNER JOIN "NestedType" AS n6 ON r2."RequiredNestedId" = n6."Id" @@ -385,7 +385,7 @@ public override async Task Contains_with_nested_and_composed_operators() @get_Item_Id='302' @entity_equality_get_Item_Id='303' (Nullable = true) -SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Name", n2."String" +SELECT r."Id", r."Name", r."OptionalRelatedId", r."RequiredRelatedId", r1."Id", r1."CollectionRootId", r1."Int", r1."Ints", r1."Name", r1."OptionalNestedId", r1."RequiredNestedId", r1."String", n."Id", n0."Id", r2."Id", n1."Id", n2."Id", n3."Id", n3."CollectionRelatedId", n3."Int", n3."Ints", n3."Name", n3."String", n."CollectionRelatedId", n."Int", n."Ints", n."Name", n."String", n0."CollectionRelatedId", n0."Int", n0."Ints", n0."Name", n0."String", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedId", s."RequiredNestedId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionRelatedId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionRelatedId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionRelatedId1", s."Int2", s."Ints2", s."Name2", s."String2", r2."CollectionRootId", r2."Int", r2."Ints", r2."Name", r2."OptionalNestedId", r2."RequiredNestedId", r2."String", n7."Id", n7."CollectionRelatedId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionRelatedId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionRelatedId", n2."Int", n2."Ints", n2."Name", n2."String" FROM "RootEntity" AS r LEFT JOIN "RelatedType" AS r1 ON r."OptionalRelatedId" = r1."Id" LEFT JOIN "NestedType" AS n ON r1."OptionalNestedId" = n."Id" @@ -395,7 +395,7 @@ public override async Task Contains_with_nested_and_composed_operators() INNER JOIN "NestedType" AS n2 ON r2."RequiredNestedId" = n2."Id" LEFT JOIN "NestedType" AS n3 ON r1."Id" = n3."CollectionRelatedId" LEFT JOIN ( - SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Name" AS "Name2", n5."String" AS "String2" + SELECT r3."Id", r3."CollectionRootId", r3."Int", r3."Ints", r3."Name", r3."OptionalNestedId", r3."RequiredNestedId", r3."String", n4."Id" AS "Id0", n5."Id" AS "Id1", n6."Id" AS "Id2", n6."CollectionRelatedId", n6."Int" AS "Int0", n6."Ints" AS "Ints0", n6."Name" AS "Name0", n6."String" AS "String0", n4."CollectionRelatedId" AS "CollectionRelatedId0", n4."Int" AS "Int1", n4."Ints" AS "Ints1", n4."Name" AS "Name1", n4."String" AS "String1", n5."CollectionRelatedId" AS "CollectionRelatedId1", n5."Int" AS "Int2", n5."Ints" AS "Ints2", n5."Name" AS "Name2", n5."String" AS "String2" FROM "RelatedType" AS r3 LEFT JOIN "NestedType" AS n4 ON r3."OptionalNestedId" = n4."Id" INNER JOIN "NestedType" AS n5 ON r3."RequiredNestedId" = n5."Id" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs index 66ce2c6d4..ca1e218c6 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs @@ -19,6 +19,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -41,6 +42,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -61,6 +63,7 @@ SELECT r0."Int" FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -82,10 +85,11 @@ public override async Task Distinct() WHERE ( SELECT count(*)::int FROM ( - SELECT DISTINCT r."Id", r0."Id" AS "Id0", r0."Int", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 + SELECT DISTINCT r."Id", r0."Id" AS "Id0", r0."Int", r0."Ints", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -104,13 +108,14 @@ public override async Task Distinct_projected(QueryTrackingBehavior queryTrackin { AssertSql( """ -SELECT r."Id", r1."Id", r1."Id0", r1."Int", r1."Name", r1."String", r1.c, r1.c0, r1.c1 +SELECT r."Id", r1."Id", r1."Id0", r1."Int", r1."Ints", r1."Name", r1."String", r1.c, r1.c0, r1.c1 FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT DISTINCT r."Id", r0."Id" AS "Id0", r0."Int", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 + SELECT DISTINCT r."Id", r0."Id" AS "Id0", r0."Int", r0."Ints", r0."Name", r0."String", r0."NestedCollection" AS c, r0."OptionalNested" AS c0, r0."RequiredNested" AS c1 FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -118,7 +123,7 @@ FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "RequiredNested" jsonb )) WITH ORDINALITY AS r0 ) AS r1 ON TRUE -ORDER BY r."Id" NULLS FIRST, r1."Id0" NULLS FIRST, r1."Int" NULLS FIRST, r1."Name" NULLS FIRST +ORDER BY r."Id" NULLS FIRST, r1."Id0" NULLS FIRST, r1."Int" NULLS FIRST, r1."Ints" NULLS FIRST, r1."Name" NULLS FIRST """); } } @@ -207,10 +212,11 @@ public override async Task GroupBy() WHERE 16 IN ( SELECT COALESCE(sum(r1."Int"), 0)::int FROM ( - SELECT r0."Id" AS "Id0", r0."Int", r0."Name", r0."String", r0."String" AS "Key" + SELECT r0."Id" AS "Id0", r0."Int", r0."Ints", r0."Name", r0."String", r0."String" AS "Key" FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -234,6 +240,7 @@ SELECT max(n."Int") FROM ROWS FROM (jsonb_to_recordset(r0."NestedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n)), 0)::int diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..eb00c7d3a --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,85 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.OwnedJson; + +public class OwnedJsonPrimitiveCollectionNpgsqlTest(OwnedJsonNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : OwnedJsonPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] = 1 +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE 3 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE 2 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" +FROM "RootEntity" AS r +WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(i0.value), 0)::int + FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i0(value)) +FROM "RootEntity" AS r +WHERE ( + SELECT COALESCE(sum(i.value), 0)::int + FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs index d703a7e1c..6cbc69dfc 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs @@ -223,11 +223,12 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q { AssertSql( """ -SELECT r."Id", r0."Id", r0."Int", r0."Name", r0."String", r0."NestedCollection", r0."OptionalNested", r0."RequiredNested" +SELECT r."Id", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r0."NestedCollection", r0."OptionalNested", r0."RequiredNested" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text, "NestedCollection" jsonb, @@ -246,11 +247,12 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer { AssertSql( """ -SELECT r."Id", n."Id", n."Int", n."Name", n."String" +SELECT r."Id", n."Id", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE @@ -266,11 +268,12 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer { AssertSql( """ -SELECT r."Id", n."Id", n."Int", n."Name", n."String" +SELECT r."Id", n."Id", n."Int", n."Ints", n."Name", n."String" FROM "RootEntity" AS r JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."OptionalRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, + "Ints" integer[], "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs index cec5cdda5..2301219e4 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs @@ -12,7 +12,7 @@ public override async Task Count() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r1."Id", r1."Int", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Name", r8."String", r2."Id", r2."Int", r2."Name", r2."String", r3."Id", r3."Int", r3."Name", r3."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Ints", r8."Name", r8."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -22,7 +22,7 @@ public override async Task Count() LEFT JOIN "RequiredRelated_RequiredNested" AS r3 ON r1."RootEntityId" = r3."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Name" AS "Name2", r6."String" AS "String2" + SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Ints" AS "Ints0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Ints" AS "Ints1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Ints" AS "Ints2", r6."Name" AS "Name2", r6."String" AS "String2" FROM "RelatedCollection" AS r4 LEFT JOIN "RelatedCollection_OptionalNested" AS r5 ON r4."RootEntityId" = r5."RelatedTypeRootEntityId" AND r4."Id" = r5."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r6 ON r4."RootEntityId" = r6."RelatedTypeRootEntityId" AND r4."Id" = r6."RelatedTypeId" @@ -43,7 +43,7 @@ public override async Task Where() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r1."Id", r1."Int", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Name", r8."String", r2."Id", r2."Int", r2."Name", r2."String", r3."Id", r3."Int", r3."Name", r3."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Ints", r8."Name", r8."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -53,7 +53,7 @@ public override async Task Where() LEFT JOIN "RequiredRelated_RequiredNested" AS r3 ON r1."RootEntityId" = r3."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Name" AS "Name2", r6."String" AS "String2" + SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Ints" AS "Ints0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Ints" AS "Ints1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Ints" AS "Ints2", r6."Name" AS "Name2", r6."String" AS "String2" FROM "RelatedCollection" AS r4 LEFT JOIN "RelatedCollection_OptionalNested" AS r5 ON r4."RootEntityId" = r5."RelatedTypeRootEntityId" AND r4."Id" = r5."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r6 ON r4."RootEntityId" = r6."RelatedTypeRootEntityId" AND r4."Id" = r6."RelatedTypeId" @@ -74,7 +74,7 @@ public override async Task OrderBy_ElementAt() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r1."Id", r1."Int", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Name", r8."String", r2."Id", r2."Int", r2."Name", r2."String", r3."Id", r3."Int", r3."Name", r3."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Ints", r8."Name", r8."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -84,7 +84,7 @@ public override async Task OrderBy_ElementAt() LEFT JOIN "RequiredRelated_RequiredNested" AS r3 ON r1."RootEntityId" = r3."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Name" AS "Name2", r6."String" AS "String2" + SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Ints" AS "Ints0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Ints" AS "Ints1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Ints" AS "Ints2", r6."Name" AS "Name2", r6."String" AS "String2" FROM "RelatedCollection" AS r4 LEFT JOIN "RelatedCollection_OptionalNested" AS r5 ON r4."RootEntityId" = r5."RelatedTypeRootEntityId" AND r4."Id" = r5."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r6 ON r4."RootEntityId" = r6."RelatedTypeRootEntityId" AND r4."Id" = r6."RelatedTypeId" @@ -109,7 +109,7 @@ public override async Task Distinct() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r2."Id", r2."Int", r2."Name", r2."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Name", r9."String", r3."Id", r3."Int", r3."Name", r3."String", r4."Id", r4."Int", r4."Name", r4."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Ints", r9."Name", r9."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -119,7 +119,7 @@ public override async Task Distinct() LEFT JOIN "RequiredRelated_RequiredNested" AS r4 ON r2."RootEntityId" = r4."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Name" AS "Name2", r7."String" AS "String2" + SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Ints", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Ints" AS "Ints0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Ints" AS "Ints1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Ints" AS "Ints2", r7."Name" AS "Name2", r7."String" AS "String2" FROM "RelatedCollection" AS r5 LEFT JOIN "RelatedCollection_OptionalNested" AS r6 ON r5."RootEntityId" = r6."RelatedTypeRootEntityId" AND r5."Id" = r6."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r7 ON r5."RootEntityId" = r7."RelatedTypeRootEntityId" AND r5."Id" = r7."RelatedTypeId" @@ -129,7 +129,7 @@ LEFT JOIN ( WHERE ( SELECT count(*)::int FROM ( - SELECT DISTINCT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String" + SELECT DISTINCT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String" FROM "RelatedCollection" AS r0 WHERE r."Id" = r0."RootEntityId" ) AS r1) = 2 @@ -145,12 +145,12 @@ public override async Task Distinct_projected(QueryTrackingBehavior queryTrackin { AssertSql( """ -SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."Id00", s."Int00", s."Name00", s."String00", s."RelatedTypeRootEntityId00", s."RelatedTypeId00", s."Id1", s."Int1", s."Name1", s."String1" +SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."Id00", s."Int00", s."Ints00", s."Name00", s."String00", s."RelatedTypeRootEntityId00", s."RelatedTypeId00", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r1."RootEntityId", r1."Id", r1."Int", r1."Name", r1."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r4."Id" AS "Id0", r4."Int" AS "Int0", r4."Name" AS "Name0", r4."String" AS "String0", r1."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r1."RelatedTypeId" AS "RelatedTypeId0", r1."Id0" AS "Id00", r1."Int0" AS "Int00", r1."Name0" AS "Name00", r1."String0" AS "String00", r1."RelatedTypeRootEntityId0" AS "RelatedTypeRootEntityId00", r1."RelatedTypeId0" AS "RelatedTypeId00", r1."Id1", r1."Int1", r1."Name1", r1."String1" + SELECT r1."RootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r4."Id" AS "Id0", r4."Int" AS "Int0", r4."Ints" AS "Ints0", r4."Name" AS "Name0", r4."String" AS "String0", r1."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r1."RelatedTypeId" AS "RelatedTypeId0", r1."Id0" AS "Id00", r1."Int0" AS "Int00", r1."Ints0" AS "Ints00", r1."Name0" AS "Name00", r1."String0" AS "String00", r1."RelatedTypeRootEntityId0" AS "RelatedTypeRootEntityId00", r1."RelatedTypeId0" AS "RelatedTypeId00", r1."Id1", r1."Int1", r1."Ints1", r1."Name1", r1."String1" FROM ( - SELECT DISTINCT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r2."RelatedTypeRootEntityId", r2."RelatedTypeId", r2."Id" AS "Id0", r2."Int" AS "Int0", r2."Name" AS "Name0", r2."String" AS "String0", r3."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r3."RelatedTypeId" AS "RelatedTypeId0", r3."Id" AS "Id1", r3."Int" AS "Int1", r3."Name" AS "Name1", r3."String" AS "String1" + SELECT DISTINCT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r2."RelatedTypeRootEntityId", r2."RelatedTypeId", r2."Id" AS "Id0", r2."Int" AS "Int0", r2."Ints" AS "Ints0", r2."Name" AS "Name0", r2."String" AS "String0", r3."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r3."RelatedTypeId" AS "RelatedTypeId0", r3."Id" AS "Id1", r3."Int" AS "Int1", r3."Ints" AS "Ints1", r3."Name" AS "Name1", r3."String" AS "String1" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_OptionalNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" AND r0."Id" = r2."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r3 ON r0."RootEntityId" = r3."RelatedTypeRootEntityId" AND r0."Id" = r3."RelatedTypeId" @@ -220,7 +220,7 @@ public override async Task GroupBy() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r1."Id", r1."Int", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Name", r8."String", r2."Id", r2."Int", r2."Name", r2."String", r3."Id", r3."Int", r3."Name", r3."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r8."RelatedTypeRootEntityId", r8."Id", r8."Int", r8."Ints", r8."Name", r8."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -230,7 +230,7 @@ public override async Task GroupBy() LEFT JOIN "RequiredRelated_RequiredNested" AS r3 ON r1."RootEntityId" = r3."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Name" AS "Name2", r6."String" AS "String2" + SELECT r4."RootEntityId", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String", r5."RelatedTypeRootEntityId", r5."RelatedTypeId", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r6."RelatedTypeId" AS "RelatedTypeId0", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r7."RelatedTypeId" AS "RelatedTypeId1", r7."Id" AS "Id0", r7."Int" AS "Int0", r7."Ints" AS "Ints0", r7."Name" AS "Name0", r7."String" AS "String0", r5."Id" AS "Id1", r5."Int" AS "Int1", r5."Ints" AS "Ints1", r5."Name" AS "Name1", r5."String" AS "String1", r6."Id" AS "Id2", r6."Int" AS "Int2", r6."Ints" AS "Ints2", r6."Name" AS "Name2", r6."String" AS "String2" FROM "RelatedCollection" AS r4 LEFT JOIN "RelatedCollection_OptionalNested" AS r5 ON r4."RootEntityId" = r5."RelatedTypeRootEntityId" AND r4."Id" = r5."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r6 ON r4."RootEntityId" = r6."RelatedTypeRootEntityId" AND r4."Id" = r6."RelatedTypeId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs index 8c35b0437..5a16052bc 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs @@ -16,7 +16,7 @@ public override async Task Where_related_property() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" @@ -26,7 +26,7 @@ public override async Task Where_related_property() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -44,7 +44,7 @@ public override async Task Where_optional_related_property() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -54,7 +54,7 @@ public override async Task Where_optional_related_property() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -72,7 +72,7 @@ public override async Task Where_nested_related_property() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r2."Id", r2."Int", r2."Name", r2."String", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_RequiredNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -82,7 +82,7 @@ public override async Task Where_nested_related_property() LEFT JOIN "RequiredRelated_OptionalNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..9d0358059 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,166 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.OwnedNavigations; + +public class OwnedNavigationsPrimitiveCollectionNpgsqlTest(OwnedNavigationsNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : OwnedNavigationsPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" + FROM "RelatedCollection" AS r3 + LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r6 ON r3."RootEntityId" = r6."RelatedTypeRootEntityId" AND r3."Id" = r6."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" +WHERE cardinality(r0."Ints") = 3 +ORDER BY r."Id" NULLS FIRST, r0."RootEntityId" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."RelatedTypeRootEntityId" NULLS FIRST, o1."RelatedTypeRootEntityId" NULLS FIRST, r1."RelatedTypeRootEntityId" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST, o2."RelatedTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."RelatedTypeRootEntityId0" NULLS FIRST, s."RelatedTypeId0" NULLS FIRST, s."RelatedTypeRootEntityId1" NULLS FIRST, s."RelatedTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, r7."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" + FROM "RelatedCollection" AS r3 + LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r6 ON r3."RootEntityId" = r6."RelatedTypeRootEntityId" AND r3."Id" = r6."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" +WHERE r0."Ints"[1] = 1 +ORDER BY r."Id" NULLS FIRST, r0."RootEntityId" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."RelatedTypeRootEntityId" NULLS FIRST, o1."RelatedTypeRootEntityId" NULLS FIRST, r1."RelatedTypeRootEntityId" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST, o2."RelatedTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."RelatedTypeRootEntityId0" NULLS FIRST, s."RelatedTypeId0" NULLS FIRST, s."RelatedTypeRootEntityId1" NULLS FIRST, s."RelatedTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, r7."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" + FROM "RelatedCollection" AS r3 + LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r6 ON r3."RootEntityId" = r6."RelatedTypeRootEntityId" AND r3."Id" = r6."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" +WHERE 3 = ANY (r0."Ints") +ORDER BY r."Id" NULLS FIRST, r0."RootEntityId" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."RelatedTypeRootEntityId" NULLS FIRST, o1."RelatedTypeRootEntityId" NULLS FIRST, r1."RelatedTypeRootEntityId" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST, o2."RelatedTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."RelatedTypeRootEntityId0" NULLS FIRST, s."RelatedTypeId0" NULLS FIRST, s."RelatedTypeRootEntityId1" NULLS FIRST, s."RelatedTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, r7."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" + FROM "RelatedCollection" AS r3 + LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r6 ON r3."RootEntityId" = r6."RelatedTypeRootEntityId" AND r3."Id" = r6."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" +WHERE 2 = ANY (r0."Ints") +ORDER BY r."Id" NULLS FIRST, r0."RootEntityId" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."RelatedTypeRootEntityId" NULLS FIRST, o1."RelatedTypeRootEntityId" NULLS FIRST, r1."RelatedTypeRootEntityId" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST, o2."RelatedTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."RelatedTypeRootEntityId0" NULLS FIRST, s."RelatedTypeId0" NULLS FIRST, s."RelatedTypeRootEntityId1" NULLS FIRST, s."RelatedTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, r7."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."RelatedTypeRootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" + FROM "RelatedCollection" AS r3 + LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r6 ON r3."RootEntityId" = r6."RelatedTypeRootEntityId" AND r3."Id" = r6."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" +WHERE cardinality(r1."Ints") = 3 +ORDER BY r."Id" NULLS FIRST, r0."RootEntityId" NULLS FIRST, r1."RelatedTypeRootEntityId" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."RelatedTypeRootEntityId" NULLS FIRST, o1."RelatedTypeRootEntityId" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST, o2."RelatedTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."RelatedTypeRootEntityId0" NULLS FIRST, s."RelatedTypeId0" NULLS FIRST, s."RelatedTypeRootEntityId1" NULLS FIRST, s."RelatedTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, r7."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(i0.value), 0)::int + FROM unnest(r0."Ints") AS i0(value)) +FROM "RootEntity" AS r +LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" +WHERE ( + SELECT COALESCE(sum(i.value), 0)::int + FROM unnest(r0."Ints") AS i(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsProjectionNpgsqlTest.cs index ae7ced81e..be883cf10 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsProjectionNpgsqlTest.cs @@ -12,7 +12,7 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -22,7 +22,7 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -95,7 +95,7 @@ public override async Task Select_related(QueryTrackingBehavior queryTrackingBeh { AssertSql( """ -SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -114,7 +114,7 @@ public override async Task Select_optional_related(QueryTrackingBehavior queryTr { AssertSql( """ -SELECT o."RootEntityId", o."Id", o."Int", o."Name", o."String", r."Id", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String" +SELECT o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."Id", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -133,7 +133,7 @@ public override async Task Select_required_nested_on_required_related(QueryTrack { AssertSql( """ -SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_RequiredNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -149,7 +149,7 @@ public override async Task Select_optional_nested_on_required_related(QueryTrack { AssertSql( """ -SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -165,7 +165,7 @@ public override async Task Select_required_nested_on_optional_related(QueryTrack { AssertSql( """ -SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String" +SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_RequiredNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -181,7 +181,7 @@ public override async Task Select_optional_nested_on_optional_related(QueryTrack { AssertSql( """ -SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String" +SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -197,7 +197,7 @@ public override async Task Select_required_related_via_optional_navigation(Query { AssertSql( """ -SELECT r1."RootEntityId", r1."Id", r1."Int", r1."Name", r1."String", r."Id", r0."Id", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", r4."Id", r4."Int", r4."Name", r4."String", r2."Id", r2."Int", r2."Name", r2."String", r3."Id", r3."Int", r3."Name", r3."String" +SELECT r1."RootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r."Id", r0."Id", r2."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String" FROM "RootReferencingEntity" AS r LEFT JOIN "RootEntity" AS r0 ON r."RootEntityId" = r0."Id" LEFT JOIN "RequiredRelated" AS r1 ON r0."Id" = r1."RootEntityId" @@ -221,10 +221,10 @@ public override async Task Select_related_collection(QueryTrackingBehavior query { AssertSql( """ -SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2" +SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2" FROM "RootEntity" AS r LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r2."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r2."RelatedTypeId" AS "RelatedTypeId0", r3."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r3."RelatedTypeId" AS "RelatedTypeId1", r3."Id" AS "Id0", r3."Int" AS "Int0", r3."Name" AS "Name0", r3."String" AS "String0", r1."Id" AS "Id1", r1."Int" AS "Int1", r1."Name" AS "Name1", r1."String" AS "String1", r2."Id" AS "Id2", r2."Int" AS "Int2", r2."Name" AS "Name2", r2."String" AS "String2" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r2."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r2."RelatedTypeId" AS "RelatedTypeId0", r3."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r3."RelatedTypeId" AS "RelatedTypeId1", r3."Id" AS "Id0", r3."Int" AS "Int0", r3."Ints" AS "Ints0", r3."Name" AS "Name0", r3."String" AS "String0", r1."Id" AS "Id1", r1."Int" AS "Int1", r1."Ints" AS "Ints1", r1."Name" AS "Name1", r1."String" AS "String1", r2."Id" AS "Id2", r2."Int" AS "Int2", r2."Ints" AS "Ints2", r2."Name" AS "Name2", r2."String" AS "String2" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" AND r0."Id" = r2."RelatedTypeId" @@ -243,7 +243,7 @@ public override async Task Select_nested_collection_on_required_related(QueryTra { AssertSql( """ -SELECT r."Id", r0."RootEntityId", r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r."Id", r0."RootEntityId", r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -260,7 +260,7 @@ public override async Task Select_nested_collection_on_optional_related(QueryTra { AssertSql( """ -SELECT r."Id", o."RootEntityId", o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String" +SELECT r."Id", o."RootEntityId", o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -277,7 +277,7 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q { AssertSql( """ -SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r2."RelatedTypeRootEntityId", r2."RelatedTypeId", r3."RelatedTypeRootEntityId", r3."RelatedTypeId", r3."Id", r3."Int", r3."Name", r3."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r2."RelatedTypeRootEntityId", r2."RelatedTypeId", r3."RelatedTypeRootEntityId", r3."RelatedTypeId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r INNER JOIN "RelatedCollection" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RelatedCollection_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" @@ -296,7 +296,7 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer { AssertSql( """ -SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" INNER JOIN "RequiredRelated_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -312,7 +312,7 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer { AssertSql( """ -SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String" +SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" INNER JOIN "OptionalRelated_NestedCollection" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -330,7 +330,7 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String", o3."RelatedTypeRootEntityId", o3."Id", o3."Int", o3."Name", o3."String", s0."RootEntityId", s0."Id", s0."Int", s0."Name", s0."String", s0."RelatedTypeRootEntityId", s0."RelatedTypeId", s0."RelatedTypeRootEntityId0", s0."RelatedTypeId0", s0."RelatedTypeRootEntityId1", s0."RelatedTypeId1", s0."Id0", s0."Int0", s0."Name0", s0."String0", s0."Id1", s0."Int1", s0."Name1", s0."String1", s0."Id2", s0."Int2", s0."Name2", s0."String2", r12."RelatedTypeRootEntityId", r12."Id", r12."Int", r12."Name", r12."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", o3."RelatedTypeRootEntityId", o3."Id", o3."Int", o3."Ints", o3."Name", o3."String", s0."RootEntityId", s0."Id", s0."Int", s0."Ints", s0."Name", s0."String", s0."RelatedTypeRootEntityId", s0."RelatedTypeId", s0."RelatedTypeRootEntityId0", s0."RelatedTypeId0", s0."RelatedTypeRootEntityId1", s0."RelatedTypeId1", s0."Id0", s0."Int0", s0."Ints0", s0."Name0", s0."String0", s0."Id1", s0."Int1", s0."Ints1", s0."Name1", s0."String1", s0."Id2", s0."Int2", s0."Ints2", s0."Name2", s0."String2", r12."RelatedTypeRootEntityId", r12."Id", r12."Int", r12."Ints", r12."Name", r12."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -340,7 +340,7 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -349,7 +349,7 @@ LEFT JOIN ( LEFT JOIN "RequiredRelated_NestedCollection" AS r7 ON r0."RootEntityId" = r7."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o3 ON o."RootEntityId" = o3."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r8."RootEntityId", r8."Id", r8."Int", r8."Name", r8."String", r9."RelatedTypeRootEntityId", r9."RelatedTypeId", r10."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r10."RelatedTypeId" AS "RelatedTypeId0", r11."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r11."RelatedTypeId" AS "RelatedTypeId1", r11."Id" AS "Id0", r11."Int" AS "Int0", r11."Name" AS "Name0", r11."String" AS "String0", r9."Id" AS "Id1", r9."Int" AS "Int1", r9."Name" AS "Name1", r9."String" AS "String1", r10."Id" AS "Id2", r10."Int" AS "Int2", r10."Name" AS "Name2", r10."String" AS "String2" + SELECT r8."RootEntityId", r8."Id", r8."Int", r8."Ints", r8."Name", r8."String", r9."RelatedTypeRootEntityId", r9."RelatedTypeId", r10."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r10."RelatedTypeId" AS "RelatedTypeId0", r11."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r11."RelatedTypeId" AS "RelatedTypeId1", r11."Id" AS "Id0", r11."Int" AS "Int0", r11."Ints" AS "Ints0", r11."Name" AS "Name0", r11."String" AS "String0", r9."Id" AS "Id1", r9."Int" AS "Int1", r9."Ints" AS "Ints1", r9."Name" AS "Name1", r9."String" AS "String1", r10."Id" AS "Id2", r10."Int" AS "Int2", r10."Ints" AS "Ints2", r10."Name" AS "Name2", r10."String" AS "String2" FROM "RelatedCollection" AS r8 LEFT JOIN "RelatedCollection_OptionalNested" AS r9 ON r8."RootEntityId" = r9."RelatedTypeRootEntityId" AND r8."Id" = r9."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r10 ON r8."RootEntityId" = r10."RelatedTypeRootEntityId" AND r8."Id" = r10."RelatedTypeId" @@ -372,10 +372,10 @@ public override async Task Select_subquery_required_related_FirstOrDefault(Query { AssertSql( """ -SELECT s."RelatedTypeRootEntityId", s."Id", s."Int", s."Name", s."String" +SELECT s."RelatedTypeRootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String" + SELECT r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r0 LEFT JOIN "RequiredRelated" AS r1 ON r0."Id" = r1."RootEntityId" LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r1."RootEntityId" = r2."RelatedTypeRootEntityId" @@ -394,10 +394,10 @@ public override async Task Select_subquery_optional_related_FirstOrDefault(Query { AssertSql( """ -SELECT s."RelatedTypeRootEntityId", s."Id", s."Int", s."Name", s."String" +SELECT s."RelatedTypeRootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String" + SELECT o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String" FROM "RootEntity" AS r0 LEFT JOIN "OptionalRelated" AS o ON r0."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_RequiredNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsSetOperationsNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsSetOperationsNpgsqlTest.cs index be3a729f9..0c9b3c341 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsSetOperationsNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsSetOperationsNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task On_related() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r2."Id", r2."Int", r2."Name", r2."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Name", r9."String", r3."Id", r3."Int", r3."Name", r3."String", r4."Id", r4."Int", r4."Name", r4."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Ints", r9."Name", r9."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -24,7 +24,7 @@ public override async Task On_related() LEFT JOIN "RequiredRelated_RequiredNested" AS r4 ON r2."RootEntityId" = r4."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Name" AS "Name2", r7."String" AS "String2" + SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Ints", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Ints" AS "Ints0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Ints" AS "Ints1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Ints" AS "Ints2", r7."Name" AS "Name2", r7."String" AS "String2" FROM "RelatedCollection" AS r5 LEFT JOIN "RelatedCollection_OptionalNested" AS r6 ON r5."RootEntityId" = r6."RelatedTypeRootEntityId" AND r5."Id" = r6."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r7 ON r5."RootEntityId" = r7."RelatedTypeRootEntityId" AND r5."Id" = r7."RelatedTypeId" @@ -79,7 +79,7 @@ public override async Task On_nested() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Name", r9."String", r3."Id", r3."Int", r3."Name", r3."String", r4."Id", r4."Int", r4."Name", r4."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r3."RelatedTypeRootEntityId", r4."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r9."RelatedTypeRootEntityId", r9."Id", r9."Int", r9."Ints", r9."Name", r9."String", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."Id", r4."Int", r4."Ints", r4."Name", r4."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" @@ -89,7 +89,7 @@ public override async Task On_nested() LEFT JOIN "RequiredRelated_RequiredNested" AS r4 ON r0."RootEntityId" = r4."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Name" AS "Name2", r7."String" AS "String2" + SELECT r5."RootEntityId", r5."Id", r5."Int", r5."Ints", r5."Name", r5."String", r6."RelatedTypeRootEntityId", r6."RelatedTypeId", r7."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r7."RelatedTypeId" AS "RelatedTypeId0", r8."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r8."RelatedTypeId" AS "RelatedTypeId1", r8."Id" AS "Id0", r8."Int" AS "Int0", r8."Ints" AS "Ints0", r8."Name" AS "Name0", r8."String" AS "String0", r6."Id" AS "Id1", r6."Int" AS "Int1", r6."Ints" AS "Ints1", r6."Name" AS "Name1", r6."String" AS "String1", r7."Id" AS "Id2", r7."Int" AS "Int2", r7."Ints" AS "Ints2", r7."Name" AS "Name2", r7."String" AS "String2" FROM "RelatedCollection" AS r5 LEFT JOIN "RelatedCollection_OptionalNested" AS r6 ON r5."RootEntityId" = r6."RelatedTypeRootEntityId" AND r5."Id" = r6."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r7 ON r5."RootEntityId" = r7."RelatedTypeRootEntityId" AND r5."Id" = r7."RelatedTypeId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsStructuralEqualityNpgsqlTest.cs index 5ba7c6050..80974a575 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsStructuralEqualityNpgsqlTest.cs @@ -14,7 +14,7 @@ public override async Task Two_related() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" @@ -24,7 +24,7 @@ public override async Task Two_related() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -42,7 +42,7 @@ public override async Task Two_nested() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o1."Id", o1."Int", o1."Name", o1."String", o0."Id", o0."Int", o0."Name", o0."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r2."Id", r2."Int", r2."Name", r2."String", r1."Id", r1."Int", r1."Name", r1."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_RequiredNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -52,7 +52,7 @@ public override async Task Two_nested() LEFT JOIN "RequiredRelated_OptionalNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -70,7 +70,7 @@ public override async Task Not_equals() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" @@ -80,7 +80,7 @@ public override async Task Not_equals() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -98,7 +98,7 @@ public override async Task Related_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -108,7 +108,7 @@ public override async Task Related_with_inline_null() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -126,7 +126,7 @@ public override async Task Related_with_parameter_null() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -136,7 +136,7 @@ public override async Task Related_with_parameter_null() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -154,7 +154,7 @@ public override async Task Nested_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r0."RootEntityId", r1."RelatedTypeRootEntityId", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RequiredRelated_OptionalNested" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" @@ -164,7 +164,7 @@ public override async Task Nested_with_inline_null() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" @@ -198,7 +198,7 @@ public override async Task Two_nested_collections() AssertSql( """ -SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Name", o2."String", o0."Id", o0."Int", o0."Name", o0."String", o1."Id", o1."Int", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Name0", s."String0", s."Id1", s."Int1", s."Name1", s."String1", s."Id2", s."Int2", s."Name2", s."String2", r0."Id", r0."Int", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Name", r7."String", r1."Id", r1."Int", r1."Name", r1."String", r2."Id", r2."Int", r2."Name", r2."String" +SELECT r."Id", r."Name", o."RootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", o0."RelatedTypeRootEntityId", o1."RelatedTypeRootEntityId", r0."RootEntityId", r1."RelatedTypeRootEntityId", r2."RelatedTypeRootEntityId", o2."RelatedTypeRootEntityId", o2."Id", o2."Int", o2."Ints", o2."Name", o2."String", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", o1."Id", o1."Int", o1."Ints", o1."Name", o1."String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."RelatedTypeRootEntityId0", s."RelatedTypeId0", s."RelatedTypeRootEntityId1", s."RelatedTypeId1", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."Id1", s."Int1", s."Ints1", s."Name1", s."String1", s."Id2", s."Int2", s."Ints2", s."Name2", s."String2", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r7."RelatedTypeRootEntityId", r7."Id", r7."Int", r7."Ints", r7."Name", r7."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated" AS o ON r."Id" = o."RootEntityId" LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."RelatedTypeRootEntityId" @@ -208,7 +208,7 @@ public override async Task Two_nested_collections() LEFT JOIN "RequiredRelated_RequiredNested" AS r2 ON r0."RootEntityId" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Name" AS "Name2", r5."String" AS "String2" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r5."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId0", r5."RelatedTypeId" AS "RelatedTypeId0", r6."RelatedTypeRootEntityId" AS "RelatedTypeRootEntityId1", r6."RelatedTypeId" AS "RelatedTypeId1", r6."Id" AS "Id0", r6."Int" AS "Int0", r6."Ints" AS "Ints0", r6."Name" AS "Name0", r6."String" AS "String0", r4."Id" AS "Id1", r4."Int" AS "Int1", r4."Ints" AS "Ints1", r4."Name" AS "Name1", r4."String" AS "String1", r5."Id" AS "Id2", r5."Int" AS "Int2", r5."Ints" AS "Ints2", r5."Name" AS "Name2", r5."String" AS "String2" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_OptionalNested" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" LEFT JOIN "RelatedCollection_RequiredNested" AS r5 ON r3."RootEntityId" = r5."RelatedTypeRootEntityId" AND r3."Id" = r5."RelatedTypeId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs index cb28b46d6..514373b2d 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs @@ -16,13 +16,13 @@ public override async Task Where_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -38,13 +38,13 @@ public override async Task Where_optional_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -60,13 +60,13 @@ public override async Task Where_nested_related_property() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingPrimitiveCollectionNpgsqlTest.cs new file mode 100644 index 000000000..579e65eed --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingPrimitiveCollectionNpgsqlTest.cs @@ -0,0 +1,135 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.OwnedTableSplitting; + +public class OwnedTableSplittingPrimitiveCollectionNpgsqlTest(OwnedTableSplittingNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : OwnedTableSplittingPrimitiveCollectionRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Count() + { + await base.Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" +END = o."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" + FROM "RelatedCollection" AS r0 + LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" +WHERE cardinality(r."RequiredRelated_Ints") = 3 +ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Index() + { + await base.Index(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" +END = o."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" + FROM "RelatedCollection" AS r0 + LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" +WHERE r."RequiredRelated_Ints"[1] = 1 +ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Contains() + { + await base.Contains(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" +END = o."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" + FROM "RelatedCollection" AS r0 + LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" +WHERE 3 = ANY (r."RequiredRelated_Ints") +ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Any_predicate() + { + await base.Any_predicate(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" +END = o."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" + FROM "RelatedCollection" AS r0 + LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" +WHERE 2 = ANY (r."RequiredRelated_Ints") +ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Nested_Count() + { + await base.Nested_Count(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +FROM "RootEntity" AS r +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" +END = o."RelatedTypeRootEntityId" +LEFT JOIN ( + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" + FROM "RelatedCollection" AS r0 + LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" +) AS s ON r."Id" = s."RootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" +WHERE cardinality(r."RequiredRelated_RequiredNested_Ints") = 3 +ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST +"""); + } + + public override async Task Select_Sum() + { + await base.Select_Sum(); + + AssertSql( + """ +SELECT ( + SELECT COALESCE(sum(r1.value), 0)::int + FROM unnest(r."RequiredRelated_Ints") AS r1(value)) +FROM "RootEntity" AS r +WHERE ( + SELECT COALESCE(sum(r0.value), 0)::int + FROM unnest(r."RequiredRelated_Ints") AS r0(value)) >= 6 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingProjectionNpgsqlTest.cs index 83752a28f..32745acfa 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingProjectionNpgsqlTest.cs @@ -12,13 +12,13 @@ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavi AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -85,7 +85,7 @@ public override async Task Select_related(QueryTrackingBehavior queryTrackingBeh { AssertSql( """ -SELECT r."Id", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated_NestedCollection" AS r0 ON r."Id" = r0."RelatedTypeRootEntityId" ORDER BY r."Id" NULLS FIRST, r0."RelatedTypeRootEntityId" NULLS FIRST @@ -101,10 +101,10 @@ public override async Task Select_optional_related(QueryTrackingBehavior queryTr { AssertSql( """ -SELECT r."Id", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" +SELECT r."Id", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST """); @@ -119,7 +119,7 @@ public override async Task Select_required_nested_on_required_related(QueryTrack { AssertSql( """ -SELECT r."Id", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -133,7 +133,7 @@ public override async Task Select_optional_nested_on_required_related(QueryTrack { AssertSql( """ -SELECT r."Id", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String" +SELECT r."Id", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String" FROM "RootEntity" AS r """); } @@ -147,7 +147,7 @@ public override async Task Select_required_nested_on_optional_related(QueryTrack { AssertSql( """ -SELECT r."Id", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" +SELECT r."Id", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r """); } @@ -161,7 +161,7 @@ public override async Task Select_optional_nested_on_optional_related(QueryTrack { AssertSql( """ -SELECT r."Id", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String" +SELECT r."Id", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String" FROM "RootEntity" AS r """); } @@ -175,7 +175,7 @@ public override async Task Select_required_related_via_optional_navigation(Query { AssertSql( """ -SELECT r0."Id", r0."RequiredRelated_Id", r0."RequiredRelated_Int", r0."RequiredRelated_Name", r0."RequiredRelated_String", r."Id", r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Name", r1."String", r0."RequiredRelated_OptionalNested_Id", r0."RequiredRelated_OptionalNested_Int", r0."RequiredRelated_OptionalNested_Name", r0."RequiredRelated_OptionalNested_String", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" +SELECT r0."Id", r0."RequiredRelated_Id", r0."RequiredRelated_Int", r0."RequiredRelated_Ints", r0."RequiredRelated_Name", r0."RequiredRelated_String", r."Id", r1."RelatedTypeRootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r0."RequiredRelated_OptionalNested_Id", r0."RequiredRelated_OptionalNested_Int", r0."RequiredRelated_OptionalNested_Ints", r0."RequiredRelated_OptionalNested_Name", r0."RequiredRelated_OptionalNested_String", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Ints", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" FROM "RootReferencingEntity" AS r LEFT JOIN "RootEntity" AS r0 ON r."RootEntityId" = r0."Id" LEFT JOIN "RequiredRelated_NestedCollection" AS r1 ON r0."Id" = r1."RelatedTypeRootEntityId" @@ -196,10 +196,10 @@ public override async Task Select_related_collection(QueryTrackingBehavior query { AssertSql( """ -SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String" +SELECT r."Id", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -216,7 +216,7 @@ public override async Task Select_nested_collection_on_required_related(QueryTra { AssertSql( """ -SELECT r."Id", r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Name", r0."String" +SELECT r."Id", r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String" FROM "RootEntity" AS r LEFT JOIN "RequiredRelated_NestedCollection" AS r0 ON r."Id" = r0."RelatedTypeRootEntityId" ORDER BY r."Id" NULLS FIRST, r0."RelatedTypeRootEntityId" NULLS FIRST @@ -232,10 +232,10 @@ public override async Task Select_nested_collection_on_optional_related(QueryTra { AssertSql( """ -SELECT r."Id", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String" +SELECT r."Id", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST """); @@ -250,7 +250,7 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q { AssertSql( """ -SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id", r1."Int", r1."Name", r1."String", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" +SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r."Id", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RootEntity" AS r INNER JOIN "RelatedCollection" AS r0 ON r."Id" = r0."RootEntityId" LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" @@ -267,7 +267,7 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer { AssertSql( """ -SELECT r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Name", r0."String" +SELECT r0."RelatedTypeRootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String" FROM "RootEntity" AS r INNER JOIN "RequiredRelated_NestedCollection" AS r0 ON r."Id" = r0."RelatedTypeRootEntityId" """); @@ -282,10 +282,10 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer { AssertSql( """ -SELECT o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String" +SELECT o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String" FROM "RootEntity" AS r INNER JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" """); } @@ -301,22 +301,22 @@ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTra AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String", o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Name", o0."String", s0."RootEntityId", s0."Id", s0."Int", s0."Name", s0."String", s0."RelatedTypeRootEntityId", s0."RelatedTypeId", s0."Id0", s0."Int0", s0."Name0", s0."String0", s0."OptionalNested_Id", s0."OptionalNested_Int", s0."OptionalNested_Name", s0."OptionalNested_String", s0."RequiredNested_Id", s0."RequiredNested_Int", s0."RequiredNested_Name", s0."RequiredNested_String", r5."RelatedTypeRootEntityId", r5."Id", r5."Int", r5."Name", r5."String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String", o0."RelatedTypeRootEntityId", o0."Id", o0."Int", o0."Ints", o0."Name", o0."String", s0."RootEntityId", s0."Id", s0."Int", s0."Ints", s0."Name", s0."String", s0."RelatedTypeRootEntityId", s0."RelatedTypeId", s0."Id0", s0."Int0", s0."Ints0", s0."Name0", s0."String0", s0."OptionalNested_Id", s0."OptionalNested_Int", s0."OptionalNested_Ints", s0."OptionalNested_Name", s0."OptionalNested_String", s0."RequiredNested_Id", s0."RequiredNested_Int", s0."RequiredNested_Ints", s0."RequiredNested_Name", s0."RequiredNested_String", r5."RelatedTypeRootEntityId", r5."Id", r5."Int", r5."Ints", r5."Name", r5."String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" LEFT JOIN "OptionalRelated_NestedCollection" AS o0 ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o0."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r4."Id" AS "Id0", r4."Int" AS "Int0", r4."Name" AS "Name0", r4."String" AS "String0", r3."OptionalNested_Id", r3."OptionalNested_Int", r3."OptionalNested_Name", r3."OptionalNested_String", r3."RequiredNested_Id", r3."RequiredNested_Int", r3."RequiredNested_Name", r3."RequiredNested_String" + SELECT r3."RootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r4."RelatedTypeRootEntityId", r4."RelatedTypeId", r4."Id" AS "Id0", r4."Int" AS "Int0", r4."Ints" AS "Ints0", r4."Name" AS "Name0", r4."String" AS "String0", r3."OptionalNested_Id", r3."OptionalNested_Int", r3."OptionalNested_Ints", r3."OptionalNested_Name", r3."OptionalNested_String", r3."RequiredNested_Id", r3."RequiredNested_Int", r3."RequiredNested_Ints", r3."RequiredNested_Name", r3."RequiredNested_String" FROM "RelatedCollection" AS r3 LEFT JOIN "RelatedCollection_NestedCollection" AS r4 ON r3."RootEntityId" = r4."RelatedTypeRootEntityId" AND r3."Id" = r4."RelatedTypeId" ) AS s0 ON r."Id" = s0."RootEntityId" @@ -337,10 +337,10 @@ public override async Task Select_subquery_required_related_FirstOrDefault(Query { AssertSql( """ -SELECT r1."Id", r1."RequiredRelated_RequiredNested_Id", r1."RequiredRelated_RequiredNested_Int", r1."RequiredRelated_RequiredNested_Name", r1."RequiredRelated_RequiredNested_String" +SELECT r1."Id", r1."RequiredRelated_RequiredNested_Id", r1."RequiredRelated_RequiredNested_Int", r1."RequiredRelated_RequiredNested_Ints", r1."RequiredRelated_RequiredNested_Name", r1."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r0."Id", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" + SELECT r0."Id", r0."RequiredRelated_RequiredNested_Id", r0."RequiredRelated_RequiredNested_Int", r0."RequiredRelated_RequiredNested_Ints", r0."RequiredRelated_RequiredNested_Name", r0."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r0 ORDER BY r0."Id" NULLS FIRST LIMIT 1 @@ -357,10 +357,10 @@ public override async Task Select_subquery_optional_related_FirstOrDefault(Query { AssertSql( """ -SELECT r1."Id", r1."OptionalRelated_RequiredNested_Id", r1."OptionalRelated_RequiredNested_Int", r1."OptionalRelated_RequiredNested_Name", r1."OptionalRelated_RequiredNested_String" +SELECT r1."Id", r1."OptionalRelated_RequiredNested_Id", r1."OptionalRelated_RequiredNested_Int", r1."OptionalRelated_RequiredNested_Ints", r1."OptionalRelated_RequiredNested_Name", r1."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN LATERAL ( - SELECT r0."Id", r0."OptionalRelated_RequiredNested_Id", r0."OptionalRelated_RequiredNested_Int", r0."OptionalRelated_RequiredNested_Name", r0."OptionalRelated_RequiredNested_String" + SELECT r0."Id", r0."OptionalRelated_RequiredNested_Id", r0."OptionalRelated_RequiredNested_Int", r0."OptionalRelated_RequiredNested_Ints", r0."OptionalRelated_RequiredNested_Name", r0."OptionalRelated_RequiredNested_String" FROM "RootEntity" AS r0 ORDER BY r0."Id" NULLS FIRST LIMIT 1 diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingStructuralEqualityNpgsqlTest.cs index 478a482a2..ded85494d 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingStructuralEqualityNpgsqlTest.cs @@ -14,13 +14,13 @@ public override async Task Two_related() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -36,13 +36,13 @@ public override async Task Two_nested() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -58,13 +58,13 @@ public override async Task Not_equals() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" @@ -80,18 +80,18 @@ public override async Task Related_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" -WHERE r."OptionalRelated_Id" IS NULL OR r."OptionalRelated_Int" IS NULL OR r."OptionalRelated_Name" IS NULL OR r."OptionalRelated_String" IS NULL +WHERE r."OptionalRelated_Id" IS NULL OR r."OptionalRelated_Int" IS NULL OR r."OptionalRelated_Ints" IS NULL OR r."OptionalRelated_Name" IS NULL OR r."OptionalRelated_String" IS NULL ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST """); } @@ -102,19 +102,19 @@ public override async Task Related_with_parameter_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" WHERE CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END IS NULL ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST """); @@ -126,18 +126,18 @@ public override async Task Nested_with_inline_null() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" LEFT JOIN "RequiredRelated_NestedCollection" AS r2 ON r."Id" = r2."RelatedTypeRootEntityId" -WHERE r."RequiredRelated_OptionalNested_Id" IS NULL OR r."RequiredRelated_OptionalNested_Int" IS NULL OR r."RequiredRelated_OptionalNested_Name" IS NULL OR r."RequiredRelated_OptionalNested_String" IS NULL +WHERE r."RequiredRelated_OptionalNested_Id" IS NULL OR r."RequiredRelated_OptionalNested_Int" IS NULL OR r."RequiredRelated_OptionalNested_Ints" IS NULL OR r."RequiredRelated_OptionalNested_Name" IS NULL OR r."RequiredRelated_OptionalNested_String" IS NULL ORDER BY r."Id" NULLS FIRST, o."RelatedTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."RelatedTypeRootEntityId" NULLS FIRST, s."RelatedTypeId" NULLS FIRST, s."Id0" NULLS FIRST, r2."RelatedTypeRootEntityId" NULLS FIRST """); } @@ -164,13 +164,13 @@ public override async Task Two_nested_collections() AssertSql( """ -SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" +SELECT r."Id", r."Name", r."OptionalRelated_Id", r."OptionalRelated_Int", r."OptionalRelated_Ints", r."OptionalRelated_Name", r."OptionalRelated_String", o."RelatedTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalRelated_OptionalNested_Id", r."OptionalRelated_OptionalNested_Int", r."OptionalRelated_OptionalNested_Ints", r."OptionalRelated_OptionalNested_Name", r."OptionalRelated_OptionalNested_String", r."OptionalRelated_RequiredNested_Id", r."OptionalRelated_RequiredNested_Int", r."OptionalRelated_RequiredNested_Ints", r."OptionalRelated_RequiredNested_Name", r."OptionalRelated_RequiredNested_String", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."RelatedTypeRootEntityId", s."RelatedTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNested_Id", s."OptionalNested_Int", s."OptionalNested_Ints", s."OptionalNested_Name", s."OptionalNested_String", s."RequiredNested_Id", s."RequiredNested_Int", s."RequiredNested_Ints", s."RequiredNested_Name", s."RequiredNested_String", r."RequiredRelated_Id", r."RequiredRelated_Int", r."RequiredRelated_Ints", r."RequiredRelated_Name", r."RequiredRelated_String", r2."RelatedTypeRootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r."RequiredRelated_OptionalNested_Id", r."RequiredRelated_OptionalNested_Int", r."RequiredRelated_OptionalNested_Ints", r."RequiredRelated_OptionalNested_Name", r."RequiredRelated_OptionalNested_String", r."RequiredRelated_RequiredNested_Id", r."RequiredRelated_RequiredNested_Int", r."RequiredRelated_RequiredNested_Ints", r."RequiredRelated_RequiredNested_Name", r."RequiredRelated_RequiredNested_String" FROM "RootEntity" AS r LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE - WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" + WHEN r."OptionalRelated_Id" IS NOT NULL AND r."OptionalRelated_Int" IS NOT NULL AND r."OptionalRelated_Ints" IS NOT NULL AND r."OptionalRelated_Name" IS NOT NULL AND r."OptionalRelated_String" IS NOT NULL THEN r."Id" END = o."RelatedTypeRootEntityId" LEFT JOIN ( - SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Name", r0."RequiredNested_String" + SELECT r0."RootEntityId", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."RelatedTypeRootEntityId", r1."RelatedTypeId", r1."Id" AS "Id0", r1."Int" AS "Int0", r1."Ints" AS "Ints0", r1."Name" AS "Name0", r1."String" AS "String0", r0."OptionalNested_Id", r0."OptionalNested_Int", r0."OptionalNested_Ints", r0."OptionalNested_Name", r0."OptionalNested_String", r0."RequiredNested_Id", r0."RequiredNested_Int", r0."RequiredNested_Ints", r0."RequiredNested_Name", r0."RequiredNested_String" FROM "RelatedCollection" AS r0 LEFT JOIN "RelatedCollection_NestedCollection" AS r1 ON r0."RootEntityId" = r1."RelatedTypeRootEntityId" AND r0."Id" = r1."RelatedTypeId" ) AS s ON r."Id" = s."RootEntityId" diff --git a/test/EFCore.PG.FunctionalTests/Query/PrecompiledQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/PrecompiledQueryNpgsqlTest.cs index 93555b7b9..c25515064 100644 --- a/test/EFCore.PG.FunctionalTests/Query/PrecompiledQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/PrecompiledQueryNpgsqlTest.cs @@ -1793,13 +1793,13 @@ public override async Task Contains_with_parameterized_collection() AssertSql( """ -@ids={ '1' +@p={ '1' '2' '3' } (DbType = Object) SELECT b."Id", b."Name", b."Json" FROM "Blogs" AS b -WHERE b."Id" = ANY (@ids) +WHERE b."Id" = ANY (@p) """); } diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs new file mode 100644 index 000000000..810990436 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; + +public class NpgsqlBoolTypeTest(NpgsqlBoolTypeTest.BoolTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='True' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='True' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS boolean)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":false,"Value":false}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='False' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(FALSE::boolean)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS boolean))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class BoolTypeFixture : NpgsqlTypeFixture + { + public override bool Value { get; } = true; + public override bool OtherValue { get; } = false; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs new file mode 100644 index 000000000..e48ee770d --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs @@ -0,0 +1,111 @@ +namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; + +public class ByteArrayTypeTest(ByteArrayTypeTest.ByteArrayTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='0x010203' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='0x010203' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (decode(j."JsonContainer" ->> 'Value', 'base64')) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"BAUGBw==","Value":"BAUGBw=="}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='0x04050607' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(encode(@Fixture_OtherValue, 'base64'))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(encode(BYTEA E'\\x04050607', 'base64'))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(encode(decode(j."JsonContainer" ->> 'OtherValue', 'base64'), 'base64'))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(encode(j."OtherValue", 'base64'))) +"""); + } + + #endregion JSON + + public class ByteArrayTypeFixture() : NpgsqlTypeFixture + { + public override byte[] Value { get; } = [1, 2, 3]; + public override byte[] OtherValue { get; } = [4, 5, 6, 7]; + + public override Func Comparer { get; } = (a, b) => a.SequenceEqual(b); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs new file mode 100644 index 000000000..cd343be5f --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; + +public class NpgsqlGuidTypeTest(NpgsqlGuidTypeTest.GuidTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='8f7331d6-cde9-44fb-8611-81fff686f280' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='8f7331d6-cde9-44fb-8611-81fff686f280' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS uuid)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"ae192c36-9004-49b2-b785-8be10d169627","Value":"ae192c36-9004-49b2-b785-8be10d169627"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='ae192c36-9004-49b2-b785-8be10d169627' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb('ae192c36-9004-49b2-b785-8be10d169627'::uuid)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS uuid))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class GuidTypeFixture : NpgsqlTypeFixture + { + public override Guid Value { get; } = new("8f7331d6-cde9-44fb-8611-81fff686f280"); + public override Guid OtherValue { get; } = new("ae192c36-9004-49b2-b785-8be10d169627"); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs new file mode 100644 index 000000000..72f71c0d3 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; + +public class StringTypeTest(StringTypeTest.StringTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='foo' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='foo' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (j."JsonContainer" ->> 'Value') = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"bar","Value":"bar"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='bar' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb('bar'::text)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."JsonContainer" ->> 'OtherValue')) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class StringTypeFixture : NpgsqlTypeFixture + { + public override string Value { get; } = "foo"; + public override string OtherValue { get; } = "bar"; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs new file mode 100644 index 000000000..b275ef366 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs @@ -0,0 +1,111 @@ +using System.Net; + +namespace Microsoft.EntityFrameworkCore.Types.Networking; + +public class NpgsqlInetTypeTest(NpgsqlInetTypeTest.InetTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='192.168.1.1' (DbType = Object) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='192.168.1.1' (DbType = Object) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS inet)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"192.168.1.2","Value":"192.168.1.2"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='192.168.1.2' (DbType = Object) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(INET '192.168.1.2'::inet)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS inet))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class InetTypeFixture : NpgsqlTypeFixture + { + public override IPAddress Value { get; } = IPAddress.Parse("192.168.1.1"); + public override IPAddress OtherValue { get; } = IPAddress.Parse("192.168.1.2"); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs new file mode 100644 index 000000000..205ba79c8 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs @@ -0,0 +1,111 @@ +using System.Net.NetworkInformation; + +namespace Microsoft.EntityFrameworkCore.Types.Networking; + +public class NpgsqlMacaddrTypeTest(NpgsqlMacaddrTypeTest.MacaddrTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='001422012345' (DbType = Object) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='001422012345' (DbType = Object) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS macaddr)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"001422012346","Value":"001422012346"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='001422012346' (DbType = Object) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(MACADDR '001422012346'::macaddr)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS macaddr))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class MacaddrTypeFixture : NpgsqlTypeFixture + { + public override PhysicalAddress Value { get; } = PhysicalAddress.Parse("00-14-22-01-23-45"); + public override PhysicalAddress OtherValue { get; } = PhysicalAddress.Parse("00-14-22-01-23-46"); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/NpgsqlTypeFixture.cs b/test/EFCore.PG.FunctionalTests/Types/NpgsqlTypeFixture.cs new file mode 100644 index 000000000..ba01ce071 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/NpgsqlTypeFixture.cs @@ -0,0 +1,6 @@ +namespace Microsoft.EntityFrameworkCore.Types; + +public abstract class NpgsqlTypeFixture : RelationalTypeFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory => NpgsqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs new file mode 100644 index 000000000..575cbce6f --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlDecimalTypeTest(NpgsqlDecimalTypeTest.DecimalTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS numeric)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":30,"Value":30}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='30' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(30.0::numeric)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS numeric))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DecimalTypeFixture : NpgsqlTypeFixture + { + public override decimal Value { get; } = 30.5m; + public override decimal OtherValue { get; } = 30m; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs new file mode 100644 index 000000000..566c29a8c --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlDoubleTypeTest(NpgsqlDoubleTypeTest.DoubleTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS double precision)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":30,"Value":30}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='30' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(30.0::double precision)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS double precision))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DoubleTypeFixture : NpgsqlTypeFixture + { + public override double Value { get; } = 30.5d; + public override double OtherValue { get; } = 30d; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs new file mode 100644 index 000000000..08b712a85 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlFloatTypeTest(NpgsqlFloatTypeTest.FloatTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='30.5' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS real)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":30,"Value":30}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='30' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(30::real)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS real))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class FloatTypeFixture : NpgsqlTypeFixture + { + public override float Value { get; } = 30.5f; + public override float OtherValue { get; } = 30f; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs new file mode 100644 index 000000000..0aa9e5b11 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlIntTypeTest(NpgsqlIntTypeTest.IntTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='-2147483648' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='-2147483648' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS integer)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":2147483647,"Value":2147483647}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='2147483647' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(2147483647::int)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS integer))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class IntTypeFixture : NpgsqlTypeFixture + { + public override int Value { get; } = int.MinValue; + public override int OtherValue { get; } = int.MaxValue; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs new file mode 100644 index 000000000..00b791c8f --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlLongTypeTest(NpgsqlLongTypeTest.LongTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='-9223372036854775808' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='-9223372036854775808' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS bigint)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":9223372036854775807,"Value":9223372036854775807}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='9223372036854775807' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(9223372036854775807::bigint)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS bigint))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class LongTypeFixture : NpgsqlTypeFixture + { + public override long Value { get; } = long.MinValue; + public override long OtherValue { get; } = long.MaxValue; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs new file mode 100644 index 000000000..93f092bc8 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Numeric; + +public class NpgsqlShortTypeTest(NpgsqlShortTypeTest.ShortTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='-32768' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='-32768' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS smallint)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":32767,"Value":32767}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='32767' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(32767::smallint)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS smallint))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class ShortTypeFixture : NpgsqlTypeFixture + { + public override short Value { get; } = short.MinValue; + public override short OtherValue { get; } = short.MaxValue; + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs new file mode 100644 index 000000000..28546743c --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class NpgsqlBoolTypeTest(NpgsqlBoolTypeTest.DateOnlyTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='01/05/2020' (DbType = Date) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='01/05/2020' (DbType = Date) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS date)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"2022-05-03","Value":"2022-05-03"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='05/03/2022' (DbType = Date) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(DATE '2022-05-03'::date)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS date))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DateOnlyTypeFixture : NpgsqlTypeFixture + { + public override DateOnly Value { get; } = new DateOnly(2020, 1, 5); + public override DateOnly OtherValue { get; } = new DateOnly(2022, 5, 3); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs new file mode 100644 index 000000000..7d9482dda --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs @@ -0,0 +1,110 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class DateTimeOffsetTypeTest(DateTimeOffsetTypeTest.DateTimeOffsetTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000+00:00' (DbType = DateTime) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000+00:00' (DbType = DateTime) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS timestamp with time zone)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"2020-01-05T13:30:45\u002B00:00","Value":"2020-01-05T13:30:45\u002B00:00"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='2020-01-05T13:30:45.0000000+00:00' (DbType = DateTime) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(TIMESTAMPTZ '2020-01-05T13:30:45+00:00'::timestamptz)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS timestamp with time zone))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DateTimeOffsetTypeFixture : NpgsqlTypeFixture + { + // Note that we don't support DateTimeOffset with Offset != 0, since the offset doesn't get stored in the database. + public override DateTimeOffset Value { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.Zero); + public override DateTimeOffset OtherValue { get; } = new DateTimeOffset(2020, 1, 5, 13, 30, 45, TimeSpan.Zero); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs new file mode 100644 index 000000000..21814622b --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs @@ -0,0 +1,111 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class DateTimeUnspecifiedTypeTest(DateTimeUnspecifiedTypeTest.DateTimeTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000' + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000' + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS timestamp without time zone)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"2022-05-03T00:00:00","Value":"2022-05-03T00:00:00"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='2022-05-03T00:00:00.0000000' + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(TIMESTAMP '2022-05-03T00:00:00'::timestamp)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS timestamp without time zone))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DateTimeTypeFixture : NpgsqlTypeFixture + { + public override string? StoreType => "timestamp without time zone"; + + public override DateTime Value { get; } = new DateTime(2020, 1, 5, 12, 30, 45, DateTimeKind.Unspecified); + public override DateTime OtherValue { get; } = new DateTime(2022, 5, 3, 0, 0, 0, DateTimeKind.Unspecified); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs new file mode 100644 index 000000000..af8ad588e --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class DateTimeUtcTypeTest(DateTimeUtcTypeTest.DateTimeTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000Z' (DbType = DateTime) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='2020-01-05T12:30:45.0000000Z' (DbType = DateTime) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS timestamp with time zone)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"2022-05-03T00:00:00Z","Value":"2022-05-03T00:00:00Z"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='2022-05-03T00:00:00.0000000Z' (DbType = DateTime) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(TIMESTAMPTZ '2022-05-03T00:00:00Z'::timestamptz)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS timestamp with time zone))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class DateTimeTypeFixture : NpgsqlTypeFixture + { + public override DateTime Value { get; } = new DateTime(2020, 1, 5, 12, 30, 45, DateTimeKind.Utc); + public override DateTime OtherValue { get; } = new DateTime(2022, 5, 3, 0, 0, 0, DateTimeKind.Utc); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs new file mode 100644 index 000000000..87e7bea64 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class NpgsqlTimeOnlyTypeTest(NpgsqlTimeOnlyTypeTest.TimeOnlyTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='12:30' (DbType = Time) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='12:30' (DbType = Time) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS time without time zone)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"14:00:00.0000000","Value":"14:00:00.0000000"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='14:00' (DbType = Time) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(TIME '14:00:00'::time without time zone)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS time without time zone))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class TimeOnlyTypeFixture : NpgsqlTypeFixture + { + public override TimeOnly Value { get; } = new TimeOnly(12, 30, 45); + public override TimeOnly OtherValue { get; } = new TimeOnly(14, 0, 0); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs new file mode 100644 index 000000000..158aac4d3 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs @@ -0,0 +1,109 @@ +namespace Microsoft.EntityFrameworkCore.Types.Temporal; + +public class NpgsqlTimeSpanTypeTest(NpgsqlTimeSpanTypeTest.TimeSpanTypeFixture fixture, ITestOutputHelper testOutputHelper) + : RelationalTypeTestBase(fixture, testOutputHelper) +{ + public override async Task Equality_in_query() + { + await base.Equality_in_query(); + + AssertSql( + """ +@Fixture_Value='12:30:45' (DbType = Object) + +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = @Fixture_Value +LIMIT 2 +"""); + } + + #region JSON + + public override async Task Query_property_within_json() + { + await base.Query_property_within_json(); + + AssertSql( + """ +@Fixture_Value='12:30:45' (DbType = Object) + +SELECT j."Id", j."OtherValue", j."Value", j."JsonContainer" +FROM "JsonTypeEntity" AS j +WHERE (CAST(j."JsonContainer" ->> 'Value' AS interval)) = @Fixture_Value +LIMIT 2 +"""); + } + + public override async Task SaveChanges_within_json() + { + await base.SaveChanges_within_json(); + + AssertSql( + """ +@p0='{"OtherValue":"14:00:00","Value":"14:00:00"}' (Nullable = false) (DbType = Object) +@p1='1' + +UPDATE "JsonTypeEntity" SET "JsonContainer" = @p0 +WHERE "Id" = @p1; +"""); + } + + public override async Task ExecuteUpdate_within_json_to_parameter() + { + await base.ExecuteUpdate_within_json_to_parameter(); + + AssertSql( + """ +@Fixture_OtherValue='14:00:00' (DbType = Object) + +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(@Fixture_OtherValue)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_constant() + { + await base.ExecuteUpdate_within_json_to_constant(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(INTERVAL '14:00:00'::interval)) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_another_json_property() + { + await base.ExecuteUpdate_within_json_to_another_json_property(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(CAST(j."JsonContainer" ->> 'OtherValue' AS interval))) +"""); + } + + public override async Task ExecuteUpdate_within_json_to_nonjson_column() + { + await base.ExecuteUpdate_within_json_to_nonjson_column(); + + AssertSql( + """ +UPDATE "JsonTypeEntity" AS j +SET "JsonContainer" = jsonb_set(j."JsonContainer", '{Value}', to_jsonb(j."OtherValue")) +"""); + } + + #endregion JSON + + public class TimeSpanTypeFixture : NpgsqlTypeFixture + { + public override TimeSpan Value { get; } = new TimeSpan(12, 30, 45); + public override TimeSpan OtherValue { get; } = new TimeSpan(14, 0, 0); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} From 6f94f23e3d81c47c5c787aa47c6868155e42ccee Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sun, 21 Sep 2025 23:09:59 +0200 Subject: [PATCH 2/3] Implement ExecuteUpdate partial update in JSON Closes #3608 --- .../Query/Internal/NpgsqlQuerySqlGenerator.cs | 68 +- ...yableMethodTranslatingExpressionVisitor.cs | 117 +++ .../ComplexJsonBulkUpdateNpgsqlTest.cs | 990 +++++++----------- .../OwnedJsonBulkUpdateNpgsqlTest.cs | 6 + 4 files changed, 531 insertions(+), 650 deletions(-) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonBulkUpdateNpgsqlTest.cs diff --git a/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs b/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs index 4a7fed392..7081d0a41 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs @@ -159,6 +159,23 @@ protected override void GenerateTop(SelectExpression selectExpression) // No TOP() in PostgreSQL, see GenerateLimitOffset } + /// + /// Generates SQL for a constant. + /// + /// The for which to generate SQL. + protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) + { + // Certain JSON functions (e.g. jsonb_set()) accept a JSONPATH argument - this is (currently) flown here as a + // SqlConstantExpression over IReadOnlyList. Render that to a string here. + if (sqlConstantExpression is { Value: IReadOnlyList path }) + { + GenerateJsonPath(ConvertJsonPathSegments(path)); + return sqlConstantExpression; + } + + return base.VisitSqlConstant(sqlConstantExpression); + } + /// /// 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 @@ -1058,31 +1075,33 @@ protected virtual Expression VisitILike(PgILikeExpression likeExpression, bool n protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression) { // TODO: Stop producing empty JsonScalarExpressions, #30768 - var path = jsonScalarExpression.Path; - if (path.Count == 0) + var segmentsPath = jsonScalarExpression.Path; + if (segmentsPath.Count == 0) { Visit(jsonScalarExpression.Json); return jsonScalarExpression; } + var path = ConvertJsonPathSegments(segmentsPath); + switch (jsonScalarExpression.TypeMapping) { // This case is for when a nested JSON entity is being accessed. We want the json/jsonb fragment in this case (not text), // so we can perform further JSON operations on it. case NpgsqlStructuralJsonTypeMapping: - GenerateJsonPath(returnsText: false); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: false, path); break; // No need to cast the output when we expect a string anyway case StringTypeMapping: - GenerateJsonPath(returnsText: true); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: true, path); break; // bytea requires special handling, since we encode the binary data as base64 inside the JSON, but that requires a special // conversion function to be extracted out to a PG bytea. case NpgsqlByteArrayTypeMapping: Sql.Append("decode("); - GenerateJsonPath(returnsText: true); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: true, path); Sql.Append(", 'base64')"); break; @@ -1092,13 +1111,13 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp case NpgsqlArrayTypeMapping arrayMapping: Sql.Append("(ARRAY(SELECT CAST(element AS ").Append(arrayMapping.ElementTypeMapping.StoreType) .Append(") FROM jsonb_array_elements_text("); - GenerateJsonPath(returnsText: false); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: false, path); Sql.Append(") WITH ORDINALITY AS t(element) ORDER BY ordinality))"); break; default: Sql.Append("CAST("); - GenerateJsonPath(returnsText: true); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: true, path); Sql.Append(" AS "); Sql.Append(jsonScalarExpression.TypeMapping!.StoreType); Sql.Append(")"); @@ -1106,19 +1125,6 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp } return jsonScalarExpression; - - void GenerateJsonPath(bool returnsText) - => this.GenerateJsonPath( - jsonScalarExpression.Json, - returnsText: returnsText, - jsonScalarExpression.Path.Select( - s => s switch - { - { PropertyName: string propertyName } - => new SqlConstantExpression(propertyName, _textTypeMapping ??= _typeMappingSource.FindMapping(typeof(string))), - { ArrayIndex: SqlExpression arrayIndex } => arrayIndex, - _ => throw new UnreachableException() - }).ToList()); } /// @@ -1148,6 +1154,11 @@ private void GenerateJsonPath(SqlExpression expression, bool returnsText, IReadO // Multiple path components Sql.Append(returnsText ? " #>> " : " #> "); + GenerateJsonPath(path); + } + + private void GenerateJsonPath(IReadOnlyList path) + { // Use simplified array literal syntax if all path components are constants for cleaner SQL if (path.All(p => p is SqlConstantExpression { Value: var pathSegment } && (pathSegment is not string s || s.All(char.IsAsciiLetterOrDigit)))) @@ -1173,6 +1184,23 @@ private void GenerateJsonPath(SqlExpression expression, bool returnsText, IReadO } } + /// + /// Converts the standard EF to an + /// (the EF built-in and don't support non-constant + /// property names, but we do via the Npgsql-specific JSON DOM support). + /// + private IReadOnlyList ConvertJsonPathSegments(IReadOnlyList path) + => path + .Select( + s => s switch + { + { PropertyName: string propertyName } + => new SqlConstantExpression(propertyName, _textTypeMapping ??= _typeMappingSource.FindMapping(typeof(string))), + { ArrayIndex: SqlExpression arrayIndex } => arrayIndex, + _ => throw new UnreachableException() + }) + .ToList(); + /// /// 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.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs index 00a0f73cc..cee1dcffa 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs @@ -1049,6 +1049,8 @@ protected override bool IsNaturallyOrdered(SelectExpression selectExpression) [{ Expression: ColumnExpression { Name: "ordinality", TableAlias: var orderingTableAlias } }] && orderingTableAlias == unnest.Alias); + #region ExecuteUpdate + /// /// 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 @@ -1103,6 +1105,121 @@ protected override bool IsValidSelectExpressionForExecuteUpdate( return true; } +#pragma warning disable EF9002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + /// + /// 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 bool TrySerializeScalarToJson( + JsonScalarExpression target, + SqlExpression value, + [NotNullWhen(true)] out SqlExpression? jsonValue) + { + var jsonTypeMapping = ((ColumnExpression)target.Json).TypeMapping!; + + if ( + // The base implementation doesn't handle serializing arbitrary SQL expressions to JSON, since that's + // database-specific. In PostgreSQL we simply do this by wrapping any expression in to_jsonb(). + !base.TrySerializeScalarToJson(target, value, out jsonValue) + // In addition, for string, numeric and bool, the base implementation simply returns the value as-is, since most databases allow + // passing these native types directly to their JSON partial update function. In PostgreSQL, jsonb_set() always requires jsonb, + // so we wrap those expression with to_jsonb() as well. + || jsonValue.TypeMapping?.StoreType is not "jsonb" and not "json") + { + switch (value.TypeMapping!.StoreType) + { + case "jsonb" or "json": + jsonValue = value; + return true; + + case "bytea": + value = _sqlExpressionFactory.Function( + "encode", + [value, _sqlExpressionFactory.Constant("base64")], + nullable: true, + argumentsPropagateNullability: [true, true], + typeof(string), + _typeMappingSource.FindMapping(typeof(string))! + ); + break; + } + + jsonValue = _sqlExpressionFactory.Function( + jsonTypeMapping.StoreType switch + { + "jsonb" => "to_jsonb", + "json" => "to_json", + _ => throw new UnreachableException() + }, + // Make sure PG interprets constant values correctly by adding explicit typing based on the target property's type mapping. + // Note that we can only be here for scalar properties, for structural types we always already get a jsonb/json value + // and don't need to add to_jsonb/to_json. + [value is SqlConstantExpression ? _sqlExpressionFactory.Convert(value, target.Type, target.TypeMapping) : value], + nullable: true, + argumentsPropagateNullability: [true], + typeof(string), + jsonTypeMapping); + } + + return true; + } +#pragma warning restore EF9002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + /// + /// 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? GenerateJsonPartialUpdateSetter( + Expression target, + SqlExpression value, + ref SqlExpression? existingSetterValue) + { + var (jsonColumn, path) = target switch + { + JsonScalarExpression j => ((ColumnExpression)j.Json, j.Path), + JsonQueryExpression j => (j.JsonColumn, j.Path), + + _ => throw new UnreachableException(), + }; + + var jsonSet = _sqlExpressionFactory.Function( + jsonColumn.TypeMapping?.StoreType switch + { + "jsonb" => "jsonb_set", + "json" => "json_set", + _ => throw new UnreachableException() + }, + arguments: + [ + existingSetterValue ?? jsonColumn, + // Hack: Rendering of JSONPATH strings happens in value generation. We can have a special expression for modify to hold the + // IReadOnlyList (just like Json{Scalar,Query}Expression), but instead we do the slight hack of packaging it + // as a constant argument; it will be unpacked and handled in SQL generation. + _sqlExpressionFactory.Constant(path, RelationalTypeMapping.NullMapping), + value + ], + nullable: true, + argumentsPropagateNullability: [true, true, true], + typeof(string), + jsonColumn.TypeMapping); + + if (existingSetterValue is null) + { + return jsonSet; + } + else + { + existingSetterValue = jsonSet; + return null; + } + } + + #endregion ExecuteUpdate + /// /// 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/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs index 6075fcc6c..e65e91758 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs @@ -5,7 +5,7 @@ public class ComplexJsonBulkUpdateNpgsqlTest( ITestOutputHelper testOutputHelper) : ComplexJsonBulkUpdateRelationalTestBase(fixture, testOutputHelper) { - // #region Delete + #region Delete public override async Task Delete_entity_with_associations() { @@ -20,635 +20,365 @@ DELETE FROM "RootEntity" AS r """); } -// public override async Task Delete_required_associate() -// { -// await base.Delete_required_associate(); - -// AssertSql(); -// } - -// public override async Task Delete_optional_associate() -// { -// await base.Delete_optional_associate(); - -// AssertSql(); -// } - -// #endregion Delete - -// #region Update properties - -// public override async Task Update_property_inside_associate() -// { -// await base.Update_property_inside_associate(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_property_inside_associate_with_special_chars() -// { -// await base.Update_property_inside_associate_with_special_chars(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.String', N'{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }') -// FROM [RootEntity] AS [r] -// WHERE JSON_VALUE([r].[RequiredAssociate], '$.String' RETURNING nvarchar(max)) = N'{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', N'{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }') -// FROM [RootEntity] AS [r] -// WHERE JSON_VALUE([r].[RequiredAssociate], '$.String') = N'{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' -// """); -// } -// } - -// public override async Task Update_property_inside_nested_associate() -// { -// await base.Update_property_inside_nested_associate(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.RequiredNestedAssociate.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_property_on_projected_associate() -// { -// await base.Update_property_on_projected_associate(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', @p) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_property_on_projected_associate_with_OrderBy_Skip() -// { -// await base.Update_property_on_projected_associate_with_OrderBy_Skip(); - -// AssertExecuteUpdateSql(); -// } - -// public override async Task Update_associate_with_null_required_property() -// { -// await base.Update_associate_with_null_required_property(); - -// AssertExecuteUpdateSql(); -// } - -// #endregion Update properties - -// #region Update association - -// public override async Task Update_associate_to_parameter() -// { -// await base.Update_associate_to_parameter(); - -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 277) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = @complex_type_p -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_nested_associate_to_parameter() -// { -// await base.Update_nested_associate_to_parameter(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 97) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.RequiredNestedAssociate', @complex_type_p) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 97) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate', JSON_QUERY(@complex_type_p)) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_associate_to_another_associate() -// { -// await base.Update_associate_to_another_associate(); - -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[OptionalAssociate] = [r].[RequiredAssociate] -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_nested_associate_to_another_nested_associate() -// { -// await base.Update_nested_associate_to_another_nested_associate(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.OptionalNestedAssociate', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate')) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.OptionalNestedAssociate', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate')) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_associate_to_inline() -// { -// await base.Update_associate_to_inline(); - -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 280) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = @complex_type_p -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_associate_to_inline_with_lambda() -// { -// await base.Update_associate_to_inline_with_lambda(); - -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = '{"Id":1000,"Int":70,"Ints":[1,2,4],"Name":"Updated associate name","String":"Updated associate string","NestedCollection":[],"OptionalNestedAssociate":null,"RequiredNestedAssociate":{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}}' -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_nested_associate_to_inline_with_lambda() -// { -// await base.Update_nested_associate_to_inline_with_lambda(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.RequiredNestedAssociate', CAST('{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}' AS json)) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.RequiredNestedAssociate', JSON_QUERY('{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}')) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_associate_to_null() -// { -// await base.Update_associate_to_null(); - -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[OptionalAssociate] = NULL -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_associate_to_null_with_lambda() -// { -// await base.Update_associate_to_null_with_lambda(); - -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[OptionalAssociate] = NULL -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_associate_to_null_parameter() -// { -// await base.Update_associate_to_null_parameter(); - -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[OptionalAssociate] = NULL -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_required_nested_associate_to_null() -// { -// await base.Update_required_nested_associate_to_null(); - -// AssertExecuteUpdateSql(); -// } - -// #endregion Update association - -// #region Update collection - -// public override async Task Update_collection_to_parameter() -// { -// await base.Update_collection_to_parameter(); - -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 571) - -// UPDATE [r] -// SET [r].[AssociateCollection] = @complex_type_p -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_nested_collection_to_parameter() -// { -// await base.Update_nested_collection_to_parameter(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 201) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.NestedCollection', @complex_type_p) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @complex_type_p='?' (Size = 201) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY(@complex_type_p)) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_nested_collection_to_inline_with_lambda() -// { -// await base.Update_nested_collection_to_inline_with_lambda(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.NestedCollection', CAST('[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name1","String":"Updated nested string1"},{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}]' AS json)) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY('[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name1","String":"Updated nested string1"},{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}]')) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_nested_collection_to_another_nested_collection() -// { -// await base.Update_nested_collection_to_another_nested_collection(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.NestedCollection', JSON_QUERY([r].[OptionalAssociate], '$.NestedCollection')) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.NestedCollection', JSON_QUERY([r].[OptionalAssociate], '$.NestedCollection')) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// } - -// public override async Task Update_collection_referencing_the_original_collection() -// { -// await base.Update_collection_referencing_the_original_collection(); - -// AssertExecuteUpdateSql(); -// } - -// public override async Task Update_inside_structural_collection() -// { -// await base.Update_inside_structural_collection(); - -// AssertExecuteUpdateSql(); -// } - -// #endregion Update collection - -// #region Update primitive collection - -// public override async Task Update_primitive_collection_to_constant() -// { -// await base.Update_primitive_collection_to_constant(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.Ints', CAST('[1,2,4]' AS json)) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints', JSON_QUERY(N'[1,2,4]')) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_primitive_collection_to_parameter() -// { -// await base.Update_primitive_collection_to_parameter(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @ints='?' (Size = 8000) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.Ints', @ints) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @ints='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints', JSON_QUERY(@ints)) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_primitive_collection_to_another_collection() -// { -// await base.Update_primitive_collection_to_another_collection(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [RequiredAssociate].modify('$.OptionalNestedAssociate.Ints', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate.Ints')) -// FROM [RootEntity] AS [r] -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.OptionalNestedAssociate.Ints', JSON_QUERY([r].[RequiredAssociate], '$.RequiredNestedAssociate.Ints')) -// FROM [RootEntity] AS [r] -// """); -// } -// } - -// public override async Task Update_inside_primitive_collection() -// { -// await base.Update_inside_primitive_collection(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (DbType = Int32) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.Ints[1]', @p) -// FROM [RootEntity] AS [r] -// WHERE ( -// SELECT COUNT(*) -// FROM OPENJSON(JSON_QUERY([r].[RequiredAssociate], '$.Ints')) AS [i]) >= 2 -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (DbType = Int32) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.Ints[1]', @p) -// FROM [RootEntity] AS [r] -// WHERE ( -// SELECT COUNT(*) -// FROM OPENJSON(JSON_QUERY([r].[RequiredAssociate], '$.Ints')) AS [i]) >= 2 -// """); -// } -// } - -// #endregion Update primitive collection - -// #region Multiple updates - -// public override async Task Update_multiple_properties_inside_same_associate() -// { -// await base.Update_multiple_properties_inside_same_associate(); - -// // Note that since two properties within the same JSON column are updated, SQL Server 2025 modify -// // is not used (it only supports modifying a single property) -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) -// @p0='?' (DbType = Int32) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY(JSON_MODIFY([r].[RequiredAssociate], '$.String', @p), '$.Int', @p0) -// FROM [RootEntity] AS [r] -// """); -// } - -// public override async Task Update_multiple_properties_inside_associates_and_on_entity_type() -// { -// await base.Update_multiple_properties_inside_associates_and_on_entity_type(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[Name] = [r].[Name] + N'Modified', -// [RequiredAssociate].modify('$.String', JSON_VALUE([r].[OptionalAssociate], '$.String' RETURNING nvarchar(max))), -// [OptionalAssociate].modify('$.RequiredNestedAssociate.String', @p) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[Name] = [r].[Name] + N'Modified', -// [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', JSON_VALUE([r].[OptionalAssociate], '$.String')), -// [r].[OptionalAssociate] = JSON_MODIFY([r].[OptionalAssociate], '$.RequiredNestedAssociate.String', @p) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// } - -// public override async Task Update_multiple_projected_associates_via_anonymous_type() -// { -// await base.Update_multiple_projected_associates_via_anonymous_type(); - -// if (Fixture.UsingJsonType) -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [RequiredAssociate].modify('$.String', JSON_VALUE([r].[OptionalAssociate], '$.String' RETURNING nvarchar(max))), -// [OptionalAssociate].modify('$.String', @p) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// else -// { -// AssertExecuteUpdateSql( -// """ -// @p='?' (Size = 4000) - -// UPDATE [r] -// SET [r].[RequiredAssociate] = JSON_MODIFY([r].[RequiredAssociate], '$.String', JSON_VALUE([r].[OptionalAssociate], '$.String')), -// [r].[OptionalAssociate] = JSON_MODIFY([r].[OptionalAssociate], '$.String', @p) -// FROM [RootEntity] AS [r] -// WHERE [r].[OptionalAssociate] IS NOT NULL -// """); -// } -// } - -// #endregion Multiple updates + public override async Task Delete_required_association() + { + await base.Delete_required_association(); + + AssertSql(); + } + + public override async Task Delete_optional_association() + { + await base.Delete_optional_association(); + + AssertSql(); + } + + #endregion Delete + + #region Update properties + + public override async Task Update_property_inside_association() + { + await base.Update_property_inside_association(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{String}', to_jsonb(@p)) +"""); + } + + public override async Task Update_property_inside_association_with_special_chars() + { + await base.Update_property_inside_association_with_special_chars(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{String}', to_jsonb('{ Some other/JSON:like text though it [isn''t]: ממש ממש לאéèéè }'::text)) +WHERE (r."RequiredRelated" ->> 'String') = '{ this may/look:like JSON but it [isn''t]: ממש ממש לאéèéè }' +"""); + } + + public override async Task Update_property_inside_nested() + { + await base.Update_property_inside_nested(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{RequiredNested,String}', to_jsonb(@p)) +"""); + } + + public override async Task Update_property_on_projected_association() + { + await base.Update_property_on_projected_association(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{String}', to_jsonb(@p)) +"""); + } + + public override async Task Update_property_on_projected_association_with_OrderBy_Skip() + { + await base.Update_property_on_projected_association_with_OrderBy_Skip(); + + AssertExecuteUpdateSql(); + } + + #endregion Update properties + + #region Update association + + public override async Task Update_association_to_parameter() + { + await base.Update_association_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = @complex_type_p +"""); + } + + public override async Task Update_nested_association_to_parameter() + { + await base.Update_nested_association_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{RequiredNested}', @complex_type_p) +"""); + } + + public override async Task Update_association_to_another_association() + { + await base.Update_association_to_another_association(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated" = r."RequiredRelated" +"""); + } + + public override async Task Update_nested_association_to_another_nested_association() + { + await base.Update_nested_association_to_another_nested_association(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{OptionalNested}', r."RequiredRelated" -> 'RequiredNested') +"""); + } + + public override async Task Update_association_to_inline() + { + await base.Update_association_to_inline(); + + AssertExecuteUpdateSql( + """ +@complex_type_p='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = @complex_type_p +"""); + } + + public override async Task Update_association_to_inline_with_lambda() + { + await base.Update_association_to_inline_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = '{"Id":1000,"Int":70,"Ints":[1,2,4],"Name":"Updated related name","String":"Updated related string","NestedCollection":[],"OptionalNested":null,"RequiredNested":{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}}' +"""); + } + + public override async Task Update_nested_association_to_inline_with_lambda() + { + await base.Update_nested_association_to_inline_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{RequiredNested}', '{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}') +"""); + } + + public override async Task Update_association_to_null() + { + await base.Update_association_to_null(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated" = NULL +"""); + } + + public override async Task Update_association_to_null_with_lambda() + { + await base.Update_association_to_null_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated" = NULL +"""); + } + + public override async Task Update_association_to_null_parameter() + { + await base.Update_association_to_null_parameter(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "OptionalRelated" = NULL +"""); + } + + #endregion Update association + + #region Update collection + + public override async Task Update_collection_to_parameter() + { + await base.Update_collection_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RelatedCollection" = @complex_type_p +"""); + } + + public override async Task Update_nested_collection_to_parameter() + { + await base.Update_nested_collection_to_parameter(); + + AssertExecuteUpdateSql( + """ +@complex_type_p='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{NestedCollection}', @complex_type_p) +"""); + } + + public override async Task Update_nested_collection_to_inline_with_lambda() + { + await base.Update_nested_collection_to_inline_with_lambda(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{NestedCollection}', '[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name1","String":"Updated nested string1"},{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}]') +"""); + } + + public override async Task Update_nested_collection_to_another_nested_collection() + { + await base.Update_nested_collection_to_another_nested_collection(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{NestedCollection}', r."OptionalRelated" -> 'NestedCollection') +WHERE (r."OptionalRelated") IS NOT NULL +"""); + } + + public override async Task Update_collection_referencing_the_original_collection() + { + await base.Update_collection_referencing_the_original_collection(); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_inside_structural_collection() + { + await base.Update_inside_structural_collection(); + + AssertExecuteUpdateSql(); + } + + #endregion Update collection + + #region Update primitive collection + + public override async Task Update_primitive_collection_to_constant() + { + await base.Update_primitive_collection_to_constant(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', to_jsonb(ARRAY[1,2,4]::integer[]::integer[])) +"""); + } + + public override async Task Update_primitive_collection_to_parameter() + { + await base.Update_primitive_collection_to_parameter(); + + AssertExecuteUpdateSql( + """ +@ints='?' (DbType = Object) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', to_jsonb(@ints)) +"""); + } + + public override async Task Update_primitive_collection_to_another_collection() + { + await base.Update_primitive_collection_to_another_collection(); + + AssertExecuteUpdateSql( + """ +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{OptionalNested,Ints}', to_jsonb((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality)))) +"""); + } + + public override async Task Update_inside_primitive_collection() + { + await base.Update_inside_primitive_collection(); + + AssertExecuteUpdateSql(); + } + + #endregion Update primitive collection + + #region Multiple updates + + public override async Task Update_multiple_properties_inside_same_association() + { + await base.Update_multiple_properties_inside_same_association(); + + AssertExecuteUpdateSql( + """ +@p='?' +@p0='?' (DbType = Int32) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(jsonb_set(r."RequiredRelated", '{String}', to_jsonb(@p)), '{Int}', to_jsonb(@p0)) +"""); + } + + public override async Task Update_multiple_properties_inside_associations_and_on_entity_type() + { + await base.Update_multiple_properties_inside_associations_and_on_entity_type(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "Name" = r."Name" || 'Modified', + "RequiredRelated" = jsonb_set(r."RequiredRelated", '{String}', to_jsonb(r."OptionalRelated" ->> 'String')), + "OptionalRelated" = jsonb_set(r."OptionalRelated", '{RequiredNested,String}', to_jsonb(@p)) +WHERE (r."OptionalRelated") IS NOT NULL +"""); + } + + public override async Task Update_multiple_projected_associations_via_anonymous_type() + { + await base.Update_multiple_projected_associations_via_anonymous_type(); + + AssertExecuteUpdateSql( + """ +@p='?' + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{String}', to_jsonb(r."OptionalRelated" ->> 'String')), + "OptionalRelated" = jsonb_set(r."OptionalRelated", '{String}', to_jsonb(@p)) +WHERE (r."OptionalRelated") IS NOT NULL +"""); + } + + #endregion Multiple updates [ConditionalFact] public virtual void Check_all_tests_overridden() diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonBulkUpdateNpgsqlTest.cs new file mode 100644 index 000000000..37d6ef243 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonBulkUpdateNpgsqlTest.cs @@ -0,0 +1,6 @@ +namespace Microsoft.EntityFrameworkCore.Query.Associations.OwnedJson; + +public class OwnedJsonBulkUpdateNpgsqlTest( + OwnedJsonNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : OwnedJsonBulkUpdateRelationalTestBase(fixture, testOutputHelper); From 831a567a3f921d3d060c54ecc2a4fa27199249f7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 22 Sep 2025 13:20:12 +0200 Subject: [PATCH 3/3] Revamp support for primitive collections within JSON Closes #3122 --- .../NpgsqlShapedQueryExpressionExtensions.cs | 97 ++- .../Conventions/NpgsqlConventionSetBuilder.cs | 5 +- ...NpgsqlPostgresModelFinalizingConvention.cs | 26 +- .../PgTableValuedFunctionExpression.cs | 2 +- .../Query/Internal/NpgsqlQuerySqlGenerator.cs | 24 +- ...yableMethodTranslatingExpressionVisitor.cs | 605 +++++++++++------- .../Internal/Mapping/NpgsqlJsonTypeMapping.cs | 10 +- .../NpgsqlStructuralJsonTypeMapping.cs | 2 +- .../Internal/Mapping/NpgsqlTypeMapping.cs | 16 +- .../Internal/NpgsqlTypeMappingSource.cs | 304 +++++---- .../NonSharedModelBulkUpdatesNpgsqlTest.cs | 6 +- .../ComplexJsonBulkUpdateNpgsqlTest.cs | 15 +- .../ComplexJsonCollectionNpgsqlTest.cs | 4 +- ...omplexJsonPrimitiveCollectionNpgsqlTest.cs | 18 +- .../ComplexJsonProjectionNpgsqlTest.cs | 6 +- ...ComplexJsonStructuralEqualityNpgsqlTest.cs | 66 +- ...mplexTableSplittingBulkUpdateNpgsqlTest.cs | 3 +- .../OwnedJsonCollectionNpgsqlTest.cs | 14 +- .../OwnedJsonPrimitiveCollectionNpgsqlTest.cs | 18 +- .../OwnedJsonProjectionNpgsqlTest.cs | 6 +- .../Query/JsonPocoQueryTest.cs | 2 +- .../Query/JsonQueryNpgsqlTest.cs | 72 +-- ...aredPrimitiveCollectionsQueryNpgsqlTest.cs | 4 +- .../Storage/NpgsqlTypeMappingSourceTest.cs | 42 ++ 24 files changed, 872 insertions(+), 495 deletions(-) diff --git a/src/EFCore.PG/Extensions/Internal/NpgsqlShapedQueryExpressionExtensions.cs b/src/EFCore.PG/Extensions/Internal/NpgsqlShapedQueryExpressionExtensions.cs index e234ac48c..4ccbbe20b 100644 --- a/src/EFCore.PG/Extensions/Internal/NpgsqlShapedQueryExpressionExtensions.cs +++ b/src/EFCore.PG/Extensions/Internal/NpgsqlShapedQueryExpressionExtensions.cs @@ -56,7 +56,7 @@ public static bool TryExtractArray( Offset: null } select && (ignorePredicate || select.Predicate is null) - // We can only apply the indexing if the JSON array is ordered by its natural ordered, i.e. by the "ordinality" column that + // We can only apply the indexing if the array is ordered by its natural ordered, i.e. by the "ordinality" column that // we created in TranslatePrimitiveCollection. For example, if another ordering has been applied (e.g. by the array elements // themselves), we can no longer simply index into the original array. && (ignoreOrderings @@ -76,6 +76,78 @@ public static bool TryExtractArray( return false; } + /// + /// If the given wraps a JSON-array-returning expression without any additional clauses (e.g. filter, + /// ordering...), returns that expression. + /// + /// + /// 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 static bool TryExtractJsonArray( + this ShapedQueryExpression source, + [NotNullWhen(true)] out SqlExpression? jsonArray, + [NotNullWhen(true)] out SqlExpression? projectedElement, + out bool isElementNullable, + bool ignoreOrderings = false, + bool ignorePredicate = false) + { + if (source.QueryExpression is SelectExpression + { + Tables: + [ + TableValuedFunctionExpression + { + Name: "jsonb_array_elements_text" or "json_array_elements_text", + Arguments: [var json] + } tvf + ], + GroupBy: [], + Having: null, + IsDistinct: false, + Limit: null, + Offset: null + } select + && (ignorePredicate || select.Predicate is null) + // We can only apply the indexing if the array is ordered by its natural ordered, i.e. by the "ordinality" column that + // we created in TranslatePrimitiveCollection. For example, if another ordering has been applied (e.g. by the array elements + // themselves), we can no longer simply index into the original array. + && (ignoreOrderings + || select.Orderings is [] + || (select.Orderings is [{ Expression: ColumnExpression { Name: "ordinality", TableAlias: var orderingTableAlias } }] + && orderingTableAlias == tvf.Alias)) + && TryGetScalarProjection(source, out var projectedScalar)) + { + jsonArray = json; + + // The projected ColumnExpression is wrapped in a Convert to apply the element type mapping - unless it happens to be text. + switch (projectedScalar) + { + case SqlUnaryExpression + { + OperatorType: ExpressionType.Convert, + Operand: ColumnExpression { IsNullable: var isNullable } + } convert: + projectedElement = convert; + isElementNullable = isNullable; + return true; + case ColumnExpression { IsNullable: var isNullable } column: + projectedElement = column; + isElementNullable = isNullable; + return true; + default: + throw new UnreachableException(); + } + } + + jsonArray = null; + projectedElement = null; + isElementNullable = false; + return false; + } + /// /// If the given wraps a without any additional clauses (e.g. filter, /// ordering...), converts that to a and returns that. @@ -86,7 +158,7 @@ public static bool TryExtractArray( /// 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 static bool TryConvertValuesToArray( + public static bool TryConvertToArray( this ShapedQueryExpression source, [NotNullWhen(true)] out SqlExpression? array, bool ignoreOrderings = false, @@ -128,6 +200,7 @@ private static bool IsPostgresArray(SqlExpression expression) { { TypeMapping: NpgsqlArrayTypeMapping } => true, { TypeMapping: NpgsqlMultirangeTypeMapping } => false, + { TypeMapping: NpgsqlJsonTypeMapping } => false, { Type: var type } when type.IsMultirange() => false, _ => true }; @@ -135,6 +208,20 @@ private static bool IsPostgresArray(SqlExpression expression) private static bool TryGetProjectedColumn( ShapedQueryExpression shapedQueryExpression, [NotNullWhen(true)] out ColumnExpression? projectedColumn) + { + if (TryGetScalarProjection(shapedQueryExpression, out var scalar) && scalar is ColumnExpression column) + { + projectedColumn = column; + return true; + } + + projectedColumn = null; + return false; + } + + private static bool TryGetScalarProjection( + ShapedQueryExpression shapedQueryExpression, + [NotNullWhen(true)] out SqlExpression? projectedScalar) { var shaperExpression = shapedQueryExpression.ShaperExpression; if (shaperExpression is UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression @@ -146,13 +233,13 @@ private static bool TryGetProjectedColumn( if (shaperExpression is ProjectionBindingExpression projectionBindingExpression && shapedQueryExpression.QueryExpression is SelectExpression selectExpression - && selectExpression.GetProjection(projectionBindingExpression) is ColumnExpression c) + && selectExpression.GetProjection(projectionBindingExpression) is SqlExpression scalar) { - projectedColumn = c; + projectedScalar = scalar; return true; } - projectedColumn = null; + projectedScalar = null; return false; } } diff --git a/src/EFCore.PG/Metadata/Conventions/NpgsqlConventionSetBuilder.cs b/src/EFCore.PG/Metadata/Conventions/NpgsqlConventionSetBuilder.cs index 12065162e..7bbdf9ed6 100644 --- a/src/EFCore.PG/Metadata/Conventions/NpgsqlConventionSetBuilder.cs +++ b/src/EFCore.PG/Metadata/Conventions/NpgsqlConventionSetBuilder.cs @@ -1,4 +1,5 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal; +using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Conventions; @@ -17,7 +18,7 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Conventions; /// public class NpgsqlConventionSetBuilder : RelationalConventionSetBuilder { - private readonly IRelationalTypeMappingSource _typeMappingSource; + private readonly NpgsqlTypeMappingSource _typeMappingSource; private readonly Version _postgresVersion; private readonly IReadOnlyList _enumDefinitions; @@ -35,7 +36,7 @@ public NpgsqlConventionSetBuilder( INpgsqlSingletonOptions npgsqlSingletonOptions) : base(dependencies, relationalDependencies) { - _typeMappingSource = typeMappingSource; + _typeMappingSource = (NpgsqlTypeMappingSource)typeMappingSource; _postgresVersion = npgsqlSingletonOptions.PostgresVersion; _enumDefinitions = npgsqlSingletonOptions.EnumDefinitions; } diff --git a/src/EFCore.PG/Metadata/Conventions/NpgsqlPostgresModelFinalizingConvention.cs b/src/EFCore.PG/Metadata/Conventions/NpgsqlPostgresModelFinalizingConvention.cs index 6298c6dca..ee9671879 100644 --- a/src/EFCore.PG/Metadata/Conventions/NpgsqlPostgresModelFinalizingConvention.cs +++ b/src/EFCore.PG/Metadata/Conventions/NpgsqlPostgresModelFinalizingConvention.cs @@ -1,4 +1,6 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal; +using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal; +using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Conventions; @@ -8,24 +10,10 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Conventions; /// /// See Model building conventions. /// -public class NpgsqlPostgresModelFinalizingConvention : IModelFinalizingConvention +public class NpgsqlPostgresModelFinalizingConvention( + NpgsqlTypeMappingSource typeMappingSource, + IReadOnlyList enumDefinitions) : IModelFinalizingConvention { - private readonly IRelationalTypeMappingSource _typeMappingSource; - private readonly IReadOnlyList _enumDefinitions; - - /// - /// Creates a new instance of . - /// - /// The type mapping source to use. - /// - public NpgsqlPostgresModelFinalizingConvention( - IRelationalTypeMappingSource typeMappingSource, - IReadOnlyList enumDefinitions) - { - _typeMappingSource = typeMappingSource; - _enumDefinitions = enumDefinitions; - } - /// public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext context) { @@ -34,7 +22,7 @@ public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, foreach (var property in entityType.GetDeclaredProperties()) { var typeMapping = (RelationalTypeMapping?)property.FindTypeMapping() - ?? _typeMappingSource.FindMapping((IProperty)property); + ?? typeMappingSource.FindMapping((IProperty)property); if (typeMapping is not null) { @@ -52,7 +40,7 @@ public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, /// protected virtual void SetupEnums(IConventionModelBuilder modelBuilder) { - foreach (var enumDefinition in _enumDefinitions) + foreach (var enumDefinition in enumDefinitions) { modelBuilder.HasPostgresEnum( enumDefinition.StoreTypeSchema, diff --git a/src/EFCore.PG/Query/Expressions/Internal/PgTableValuedFunctionExpression.cs b/src/EFCore.PG/Query/Expressions/Internal/PgTableValuedFunctionExpression.cs index 0d7f5c418..86bcd95d9 100644 --- a/src/EFCore.PG/Query/Expressions/Internal/PgTableValuedFunctionExpression.cs +++ b/src/EFCore.PG/Query/Expressions/Internal/PgTableValuedFunctionExpression.cs @@ -55,7 +55,7 @@ public PgTableValuedFunctionExpression( string alias, string name, IReadOnlyList arguments, - IReadOnlyList? columnInfos, + IReadOnlyList? columnInfos = null, bool withOrdinality = true) : base(alias, name, schema: null, builtIn: true, arguments) { diff --git a/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs b/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs index 7081d0a41..03b4a92bd 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs @@ -1086,12 +1086,19 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp switch (jsonScalarExpression.TypeMapping) { - // This case is for when a nested JSON entity is being accessed. We want the json/jsonb fragment in this case (not text), - // so we can perform further JSON operations on it. + // Nested JSON structural type. We want the json/jsonb fragment in this case (not text), so we can perform further JSON + // operations on it. case NpgsqlStructuralJsonTypeMapping: GenerateJsonPath(jsonScalarExpression.Json, returnsText: false, path); break; + // Scalar collection mapped to JSON (either because it's nested within a JSON document, or because the user explicitly + // opted for this rather than the default PG array mapping). + case NpgsqlJsonTypeMapping typeMapping: + Check.DebugAssert(typeMapping.ElementTypeMapping is not null); + GenerateJsonPath(jsonScalarExpression.Json, returnsText: false, path); + break; + // No need to cast the output when we expect a string anyway case StringTypeMapping: GenerateJsonPath(jsonScalarExpression.Json, returnsText: true, path); @@ -1105,15 +1112,10 @@ protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExp Sql.Append(", 'base64')"); break; - // Arrays require special handling; we cannot simply cast a JSON array (as text) to a PG array ([1,2,3] isn't a valid PG array - // representation). We use jsonb_array_elements_text to extract the array elements as a set, cast them to their PG element type - // and then build an array from that. - case NpgsqlArrayTypeMapping arrayMapping: - Sql.Append("(ARRAY(SELECT CAST(element AS ").Append(arrayMapping.ElementTypeMapping.StoreType) - .Append(") FROM jsonb_array_elements_text("); - GenerateJsonPath(jsonScalarExpression.Json, returnsText: false, path); - Sql.Append(") WITH ORDINALITY AS t(element) ORDER BY ordinality))"); - break; + // We should never have an NpgsqlArrayTypeMapping within a JSON document; scalar collections should be represented as an + // NpgsqlJsonTypeMapping with the appropriate ElementTypeMapping, just like in other providers. + case NpgsqlArrayTypeMapping: + throw new UnreachableException(); default: Sql.Append("CAST("); diff --git a/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs index cee1dcffa..6b906bef2 100644 --- a/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs @@ -116,47 +116,103 @@ protected override QueryableMethodTranslatingExpressionVisitor CreateSubqueryVis // a special case for geometry collections, where we use SelectExpression selectExpression; -#pragma warning disable EF1001 // SelectExpression constructors are currently internal // TODO: Parameters have no type mapping. We can check whether the expression type is one of the NTS geometry collection types, // though in a perfect world we'd actually infer this. In other words, when the type mapping of the element is inferred further on, // we'd replace the unnest expression with ST_Dump. We could even have a special expression type which means "indeterminate, must be // inferred". - if (sqlExpression.TypeMapping is { StoreTypeNameBase: "geometry" or "geography" }) - { - // TODO: For geometry collection support (not yet supported), see #2850. - selectExpression = new SelectExpression( - [new TableValuedFunctionExpression(tableAlias, "ST_Dump", [sqlExpression])], - new ColumnExpression("geom", tableAlias, elementClrType.UnwrapNullableType(), elementTypeMapping, isElementNullable), - identifier: [], // TODO - _queryCompilationContext.SqlAliasManager); - } - else +#pragma warning disable EF1001 // SelectExpression constructors are pubternal + switch (sqlExpression.TypeMapping) { - // Note that for unnest we have a special expression type extending TableValuedFunctionExpression, adding the ability to provide - // an explicit column name for its output (SELECT * FROM unnest(array) AS f(foo)). - // This is necessary since when the column name isn't explicitly specified, it is automatically identical to the table alias - // (f above); since the table alias may get uniquified by EF, this would break queries. - - // TODO: When we have metadata to determine if the element is nullable, pass that here to SelectExpression - - // Note also that with PostgreSQL unnest, the output ordering is guaranteed to be the same as the input array. However, we still - // need to add an explicit ordering on the ordinality column, since once the unnest is joined into a select, its "natural" - // orderings is lost and an explicit ordering is needed again (see #3207). - var (ordinalityColumn, ordinalityComparer) = GenerateOrdinalityIdentifier(tableAlias); - selectExpression = new SelectExpression( - [new PgUnnestExpression(tableAlias, sqlExpression, "value")], - new ColumnExpression( - "value", + case { StoreTypeNameBase: "geometry" or "geography" }: + { + // TODO: For geometry collection support (not yet supported), see #2850. + selectExpression = new SelectExpression( + [new TableValuedFunctionExpression(tableAlias, "ST_Dump", [sqlExpression])], + new ColumnExpression("geom", tableAlias, elementClrType.UnwrapNullableType(), elementTypeMapping, isElementNullable), + identifier: [], // TODO + _queryCompilationContext.SqlAliasManager); + break; + } + + // Scalar/primitive collection mapped to a PostgreSQL array (typical and default case) + case NpgsqlArrayTypeMapping or NpgsqlMultirangeTypeMapping or null: + { + // Note that for unnest we have a special expression type extending TableValuedFunctionExpression, adding the ability to provide + // an explicit column name for its output (SELECT * FROM unnest(array) AS f(foo)). + // This is necessary since when the column name isn't explicitly specified, it is automatically identical to the table alias + // (f above); since the table alias may get uniquified by EF, this would break queries. + + // TODO: When we have metadata to determine if the element is nullable, pass that here to SelectExpression + + // Note also that with PostgreSQL unnest, the output ordering is guaranteed to be the same as the input array. However, we still + // need to add an explicit ordering on the ordinality column, since once the unnest is joined into a select, its "natural" + // orderings is lost and an explicit ordering is needed again (see #3207). + var (ordinalityColumn, ordinalityComparer) = GenerateOrdinalityIdentifier(tableAlias); + selectExpression = new SelectExpression( + [new PgUnnestExpression(tableAlias, sqlExpression, "value")], + new ColumnExpression( + "value", + tableAlias, + elementClrType.UnwrapNullableType(), + elementTypeMapping, + isElementNullable), + identifier: [(ordinalityColumn, ordinalityComparer)], + _queryCompilationContext.SqlAliasManager); + + selectExpression.AppendOrdering(new OrderingExpression(ordinalityColumn, ascending: true)); + break; + } + + // Scalar/primitive collection mapped to a JSON array, like in other providers. + // Happens for scalar collections nested within JSON documents, or if the user explicitly mapped to JSON instead of + // the default PG array. + // Translate to SELECT element::int FROM jsonb_array_elements_text(...) WITH ORDINALITY + case NpgsqlJsonTypeMapping { ElementTypeMapping: not null, StoreType: var storeType }: + { + var (ordinalityColumn, ordinalityComparer) = GenerateOrdinalityIdentifier(tableAlias); + + SqlExpression elementProjection = new ColumnExpression( + "element", tableAlias, - elementClrType.UnwrapNullableType(), - elementTypeMapping, - isElementNullable), - identifier: [(ordinalityColumn, ordinalityComparer)], - _queryCompilationContext.SqlAliasManager); + typeof(string), + _typeMappingSource.FindMapping(typeof(string)), + isElementNullable); + + // If the projected type is anything other than a text, apply a cast (jsonb_array_elements_text returns text) + if (!elementTypeMapping!.StoreType.Equals("text", StringComparison.OrdinalIgnoreCase)) + { + elementProjection = _sqlExpressionFactory.Convert( + elementProjection, + elementClrType.UnwrapNullableType(), + elementTypeMapping); + } + + selectExpression = new SelectExpression( + [ + new PgTableValuedFunctionExpression( + tableAlias, + storeType switch + { + "jsonb" => "jsonb_array_elements_text", + "json" => "json_array_elements_text", + _ => throw new UnreachableException() + }, + [sqlExpression], + columnInfos: [new("element")], + withOrdinality: true) + ], + elementProjection, + identifier: [(ordinalityColumn, ordinalityComparer)], + _queryCompilationContext.SqlAliasManager); + + selectExpression.AppendOrdering(new OrderingExpression(ordinalityColumn, ascending: true)); + break; + } - selectExpression.AppendOrdering(new OrderingExpression(ordinalityColumn, ascending: true)); + default: + throw new UnreachableException(); } -#pragma warning restore EF1001 +#pragma warning restore EF1001 // SelectExpression constructors are pubternal Expression shaperExpression = new ProjectionBindingExpression( selectExpression, new ProjectionMember(), elementClrType.MakeNullable()); @@ -290,7 +346,7 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr protected override ShapedQueryExpression? TranslateAll(ShapedQueryExpression source, LambdaExpression predicate) { if ((source.TryExtractArray(out var array, ignoreOrderings: true) - || source.TryConvertValuesToArray(out array, ignoreOrderings: true)) + || source.TryConvertToArray(out array, ignoreOrderings: true)) && source.QueryExpression is SelectExpression { Tables: [{ Alias: var tableAlias }] } && TranslateLambdaExpression(source, predicate) is { } translatedPredicate) { @@ -364,177 +420,200 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr /// protected override ShapedQueryExpression? TranslateAny(ShapedQueryExpression source, LambdaExpression? predicate) { - if ((source.TryExtractArray(out var array, ignoreOrderings: true) - || source.TryConvertValuesToArray(out array, ignoreOrderings: true)) - && source.QueryExpression is SelectExpression { Tables: [{ Alias: var tableAlias }] }) + if (source.QueryExpression is SelectExpression { Tables: [{ Alias: var tableAlias }] }) { - // Pattern match: x.Array.Any() - // Translation: cardinality(x.array) > 0 instead of EXISTS (SELECT 1 FROM FROM unnest(x.Array)) - if (predicate is null) + // Pattern match: x.JsonArray.Any() + // Translation: jsonb_array_length(x.json_array) > 0 instead of EXISTS (SELECT 1 FROM FROM jsonb_array_elements(x.Array)) + if (predicate is null && source.TryExtractJsonArray(out var jsonArray, out _, out _, ignoreOrderings: true)) { return BuildSimplifiedShapedQuery( source, _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( - "cardinality", - [array], + jsonArray.TypeMapping!.StoreType switch + { + "jsonb" => "jsonb_array_length", + "json" => "json_array_length", + _ => throw new UnreachableException() + }, + [jsonArray], nullable: true, argumentsPropagateNullability: TrueArrays[1], typeof(int)), _sqlExpressionFactory.Constant(0))); } - if (TranslateLambdaExpression(source, predicate) is not SqlExpression translatedPredicate) + if (source.TryExtractArray(out var array, ignoreOrderings: true) + || source.TryConvertToArray(out array, ignoreOrderings: true)) { - return null; - } + // Pattern match: x.Array.Any() + // Translation: cardinality(x.array) > 0 instead of EXISTS (SELECT 1 FROM FROM unnest(x.Array)) + if (predicate is null) + { + return BuildSimplifiedShapedQuery( + source, + _sqlExpressionFactory.GreaterThan( + _sqlExpressionFactory.Function( + "cardinality", + [array], + nullable: true, + argumentsPropagateNullability: TrueArrays[1], + typeof(int)), + _sqlExpressionFactory.Constant(0))); + } - switch (translatedPredicate) - { - // Pattern match: new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p)) - // Translation: s.SomeText LIKE ANY (ARRAY['a','b','c']) - case LikeExpression + if (TranslateLambdaExpression(source, predicate) is not SqlExpression translatedPredicate) + { + return null; + } + + switch (translatedPredicate) + { + // Pattern match: new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p)) + // Translation: s.SomeText LIKE ANY (ARRAY['a','b','c']) + case LikeExpression { Match: var match, Pattern: ColumnExpression pattern, EscapeChar: SqlConstantExpression { Value: "" } } - when pattern.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, _sqlExpressionFactory.Any(match, array, PgAnyOperatorType.Like)); - } + when pattern.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, _sqlExpressionFactory.Any(match, array, PgAnyOperatorType.Like)); + } - // Pattern match: new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p)) - // Translation: s.SomeText LIKE ANY (ARRAY['a','b','c']) - case PgILikeExpression + // Pattern match: new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p)) + // Translation: s.SomeText LIKE ANY (ARRAY['a','b','c']) + case PgILikeExpression { Match: var match, Pattern: ColumnExpression pattern, EscapeChar: SqlConstantExpression { Value: "" } } - when pattern.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, _sqlExpressionFactory.Any(match, array, PgAnyOperatorType.ILike)); - } + when pattern.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, _sqlExpressionFactory.Any(match, array, PgAnyOperatorType.ILike)); + } - // Array overlap over non-column - // Pattern match: e.SomeArray.Any(p => ints.Contains(p)) - // Translation: @ints && s.SomeArray - case PgAnyExpression + // Array overlap over non-column + // Pattern match: e.SomeArray.Any(p => ints.Contains(p)) + // Translation: @ints && s.SomeArray + case PgAnyExpression { Item: ColumnExpression sourceColumn, Array: var otherArray } - when sourceColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Overlaps(array, otherArray)); - } + when sourceColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Overlaps(array, otherArray)); + } - // Array overlap over column - // Pattern match: new[] { 4, 5 }.Any(p => e.SomeArray.Contains(p)) - // Translation: s.SomeArray && ARRAY[4, 5] - case PgBinaryExpression + // Array overlap over column + // Pattern match: new[] { 4, 5 }.Any(p => e.SomeArray.Contains(p)) + // Translation: s.SomeArray && ARRAY[4, 5] + case PgBinaryExpression { OperatorType: PgExpressionType.Contains, Left: var otherArray, Right: PgNewArrayExpression { Expressions: [ColumnExpression sourceColumn] } } - when sourceColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Overlaps(array, otherArray)); - } + when sourceColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Overlaps(array, otherArray)); + } - #region LTree translations + #region LTree translations - // Pattern match: new[] { "q1", "q2" }.Any(q => e.SomeLTree.MatchesLQuery(q)) - // Translation: s.SomeLTree ? ARRAY['q1','q2'] - case PgBinaryExpression + // Pattern match: new[] { "q1", "q2" }.Any(q => e.SomeLTree.MatchesLQuery(q)) + // Translation: s.SomeLTree ? ARRAY['q1','q2'] + case PgBinaryExpression { OperatorType: PgExpressionType.LTreeMatches, Left: var ltree, Right: SqlUnaryExpression { OperatorType: ExpressionType.Convert, Operand: ColumnExpression lqueryColumn } } - when lqueryColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, - new PgBinaryExpression( - PgExpressionType.LTreeMatchesAny, - ltree, - _sqlExpressionFactory.ApplyTypeMapping(array, _typeMappingSource.FindMapping("lquery[]")), - typeof(bool), - typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); - } + when lqueryColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, + new PgBinaryExpression( + PgExpressionType.LTreeMatchesAny, + ltree, + _sqlExpressionFactory.ApplyTypeMapping(array, _typeMappingSource.FindMapping("lquery[]")), + typeof(bool), + typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); + } - // Pattern match: new[] { "t1", "t2" }.Any(t => t.IsAncestorOf(e.SomeLTree)) - // Translation: ARRAY['t1','t2'] @> s.SomeLTree - // Pattern match: new[] { "t1", "t2" }.Any(t => t.IsDescendantOf(e.SomeLTree)) - // Translation: ARRAY['t1','t2'] <@ s.SomeLTree - case PgBinaryExpression + // Pattern match: new[] { "t1", "t2" }.Any(t => t.IsAncestorOf(e.SomeLTree)) + // Translation: ARRAY['t1','t2'] @> s.SomeLTree + // Pattern match: new[] { "t1", "t2" }.Any(t => t.IsDescendantOf(e.SomeLTree)) + // Translation: ARRAY['t1','t2'] <@ s.SomeLTree + case PgBinaryExpression { OperatorType: (PgExpressionType.Contains or PgExpressionType.ContainedBy) and var operatorType, Left: ColumnExpression ltreeColumn, // Contains/ContainedBy can happen for non-LTree types too, so check that Right: { TypeMapping: NpgsqlLTreeTypeMapping } ltree } - when ltreeColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, - new PgBinaryExpression( - operatorType, - _sqlExpressionFactory.ApplyDefaultTypeMapping(array), - ltree, - typeof(bool), - typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); - } + when ltreeColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, + new PgBinaryExpression( + operatorType, + _sqlExpressionFactory.ApplyDefaultTypeMapping(array), + ltree, + typeof(bool), + typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); + } - // Pattern match: new[] { "t1", "t2" }.Any(t => t.MatchesLQuery(lquery)) - // Translation: ARRAY['t1','t2'] ~ lquery - // Pattern match: new[] { "t1", "t2" }.Any(t => t.MatchesLTxtQuery(ltxtquery)) - // Translation: ARRAY['t1','t2'] @ ltxtquery - case PgBinaryExpression + // Pattern match: new[] { "t1", "t2" }.Any(t => t.MatchesLQuery(lquery)) + // Translation: ARRAY['t1','t2'] ~ lquery + // Pattern match: new[] { "t1", "t2" }.Any(t => t.MatchesLTxtQuery(ltxtquery)) + // Translation: ARRAY['t1','t2'] @ ltxtquery + case PgBinaryExpression { OperatorType: PgExpressionType.LTreeMatches, Left: ColumnExpression ltreeColumn, Right: var lquery } - when ltreeColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, - new PgBinaryExpression( - PgExpressionType.LTreeMatches, - _sqlExpressionFactory.ApplyDefaultTypeMapping(array), - lquery, - typeof(bool), - typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); - } + when ltreeColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, + new PgBinaryExpression( + PgExpressionType.LTreeMatches, + _sqlExpressionFactory.ApplyDefaultTypeMapping(array), + lquery, + typeof(bool), + typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); + } - // Any within Any (i.e. intersection) - // Pattern match: ltrees.Any(t => lqueries.Any(q => t.MatchesLQuery(q))) - // Translate: ltrees ? lqueries - case PgBinaryExpression + // Any within Any (i.e. intersection) + // Pattern match: ltrees.Any(t => lqueries.Any(q => t.MatchesLQuery(q))) + // Translate: ltrees ? lqueries + case PgBinaryExpression { OperatorType: PgExpressionType.LTreeMatchesAny, Left: ColumnExpression ltreeColumn, Right: var lqueries } - when ltreeColumn.TableAlias == tableAlias: - { - return BuildSimplifiedShapedQuery( - source, - new PgBinaryExpression( - PgExpressionType.LTreeMatchesAny, - _sqlExpressionFactory.ApplyDefaultTypeMapping(array), - lqueries, - typeof(bool), - typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); - } + when ltreeColumn.TableAlias == tableAlias: + { + return BuildSimplifiedShapedQuery( + source, + new PgBinaryExpression( + PgExpressionType.LTreeMatchesAny, + _sqlExpressionFactory.ApplyDefaultTypeMapping(array), + lqueries, + typeof(bool), + typeMapping: _typeMappingSource.FindMapping(typeof(bool)))); + } - #endregion LTree translations + #endregion LTree translations + } } } @@ -590,69 +669,96 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr /// protected override ShapedQueryExpression? TranslateContains(ShapedQueryExpression source, Expression item) { - // Note that most other simplifications convert ValuesExpression to unnest over array constructor, but we avoid doing that - // here for Contains, since the relational translation for ValuesExpression is better. - if (source.TryExtractArray(out var array, ignoreOrderings: true) - && TranslateExpression(item, applyDefaultTypeMapping: false) is SqlExpression translatedItem) + switch (source) { - (translatedItem, array) = _sqlExpressionFactory.ApplyTypeMappingsOnItemAndArray(translatedItem, array); - - // We special-case null constant item and use array_position instead, since it does - // nulls correctly (but doesn't use indexes). - // TODO: Better just translate to ANY and handle in nullability processing? - // TODO: once lambda-based caching is implemented, move this to NpgsqlSqlNullabilityProcessor - // (https://github.com/dotnet/efcore/issues/17598) and do for parameters as well. - if (translatedItem is SqlConstantExpression { Value: null }) + // Contains over array, e.g. x = ANY(y.Array), or y.Array @> ARRAY[x] + // Note that most other simplifications convert ValuesExpression to unnest over array constructor, but we avoid doing that + // here for Contains, since the relational translation for ValuesExpression is better. + case var _ when source.TryExtractArray(out var array, ignoreOrderings: true) + && TranslateExpression(item, applyDefaultTypeMapping: false) is SqlExpression translatedItem: + { + (translatedItem, array) = _sqlExpressionFactory.ApplyTypeMappingsOnItemAndArray(translatedItem, array); + + // We special-case null constant item and use array_position instead, since it does + // nulls correctly (but doesn't use indexes). + // TODO: Better just translate to ANY and handle in nullability processing? + // TODO: once lambda-based caching is implemented, move this to NpgsqlSqlNullabilityProcessor + // (https://github.com/dotnet/efcore/issues/17598) and do for parameters as well. + if (translatedItem is SqlConstantExpression { Value: null }) + { + return BuildSimplifiedShapedQuery( + source, + _sqlExpressionFactory.IsNotNull( + _sqlExpressionFactory.Function( + "array_position", + [array, translatedItem], + nullable: true, + argumentsPropagateNullability: FalseArrays[2], + typeof(int)))); + } + + return array switch + { + // For array columns which have a GIN index, we translate to array containment (with @>) which uses that index. + ColumnExpression { Column: IColumn column } + when column.Table.Indexes + .Any(i => + i.Columns.Count > 0 + && i.Columns[0] == column + && i.MappedIndexes.Any(mi => mi.GetMethod()?.Equals("GIN", StringComparison.OrdinalIgnoreCase) == true)) + => BuildSimplifiedShapedQuery( + source, + _sqlExpressionFactory.Contains( + array, + _sqlExpressionFactory.NewArrayOrConstant([translatedItem], array.Type, array.TypeMapping))), + + // For constant arrays (new[] { 1, 2, 3 }) or inline arrays (new[] { 1, param, 3 }), don't do anything PG-specific for since + // the general EF Core mechanism is fine for that case: item IN (1, 2, 3). + SqlConstantExpression or PgNewArrayExpression + => base.TranslateContains(source, item), + + // Similar to ParameterExpression below, but when a bare subquery is present inside ANY(), PostgreSQL just compares + // against each of its resulting rows (just like IN). To "extract" the array result of the scalar subquery, we need + // to add an explicit cast (see #1803). + ScalarSubqueryExpression subqueryExpression + => BuildSimplifiedShapedQuery( + source, + _sqlExpressionFactory.Any( + translatedItem, + _sqlExpressionFactory.Convert( + subqueryExpression, subqueryExpression.Type, subqueryExpression.TypeMapping), + PgAnyOperatorType.Equal)), + + // For ParameterExpression, and for all other cases - e.g. array returned from some function - + // translate to e.SomeText = ANY (@p). This is superior to the general solution which will expand + // parameters to constants, since non-PG SQL does not support arrays. + // Note that this will allow indexes on the item to be used. + _ => BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Any(translatedItem, array, PgAnyOperatorType.Equal)) + }; + } + + // Contains over JSON array: array ? 'foo' for text, array @> item for bool/numeric + case var _ when source.TryExtractJsonArray(out var array, out _, out var isElementNullable, ignoreOrderings: true) + && TranslateExpression(item, applyDefaultTypeMapping: false) is SqlExpression translatedItem: { + (translatedItem, array) = _sqlExpressionFactory.ApplyTypeMappingsOnItemAndArray(translatedItem, array); + + // TODO: Null semantics - need to coalesce NULL on the item side to 'null'::jsonb. + // TODO: For constant/parameter, use JsonValueReaderWriter to produce the JSON value client-side return BuildSimplifiedShapedQuery( source, - _sqlExpressionFactory.IsNotNull( + _sqlExpressionFactory.Contains( + array, _sqlExpressionFactory.Function( - "array_position", - [array, translatedItem], + "to_jsonb", + [translatedItem is SqlConstantExpression { Value: string } + ? _sqlExpressionFactory.Convert(translatedItem, typeof(string), _typeMappingSource.FindMapping(typeof(string))) + : translatedItem], nullable: true, - argumentsPropagateNullability: FalseArrays[2], - typeof(int)))); + argumentsPropagateNullability: TrueArrays[1], + typeof(string), + _typeMappingSource.FindMapping("jsonb")))); } - - return array switch - { - // For array columns which have a GIN index, we translate to array containment (with @>) which uses that index. - ColumnExpression { Column: IColumn column } - when column.Table.Indexes - .Any(i => - i.Columns.Count > 0 - && i.Columns[0] == column - && i.MappedIndexes.Any(mi => mi.GetMethod()?.Equals("GIN", StringComparison.OrdinalIgnoreCase) == true)) - => BuildSimplifiedShapedQuery( - source, - _sqlExpressionFactory.Contains( - array, - _sqlExpressionFactory.NewArrayOrConstant([translatedItem], array.Type, array.TypeMapping))), - - // For constant arrays (new[] { 1, 2, 3 }) or inline arrays (new[] { 1, param, 3 }), don't do anything PG-specific for since - // the general EF Core mechanism is fine for that case: item IN (1, 2, 3). - SqlConstantExpression or PgNewArrayExpression - => base.TranslateContains(source, item), - - // Similar to ParameterExpression below, but when a bare subquery is present inside ANY(), PostgreSQL just compares - // against each of its resulting rows (just like IN). To "extract" the array result of the scalar subquery, we need - // to add an explicit cast (see #1803). - ScalarSubqueryExpression subqueryExpression - => BuildSimplifiedShapedQuery( - source, - _sqlExpressionFactory.Any( - translatedItem, - _sqlExpressionFactory.Convert( - subqueryExpression, subqueryExpression.Type, subqueryExpression.TypeMapping), - PgAnyOperatorType.Equal)), - - // For ParameterExpression, and for all other cases - e.g. array returned from some function - - // translate to e.SomeText = ANY (@p). This is superior to the general solution which will expand - // parameters to constants, since non-PG SQL does not support arrays. - // Note that this will allow indexes on the item to be used. - _ => BuildSimplifiedShapedQuery(source, _sqlExpressionFactory.Any(translatedItem, array, PgAnyOperatorType.Equal)) - }; } return base.TranslateContains(source, item); @@ -667,22 +773,51 @@ ScalarSubqueryExpression subqueryExpression protected override ShapedQueryExpression? TranslateCount(ShapedQueryExpression source, LambdaExpression? predicate) { // Simplify x.Array.Count() => cardinality(x.Array) instead of SELECT COUNT(*) FROM unnest(x.Array) - if (predicate is null && source.TryExtractArray(out var array, ignoreOrderings: true)) + if (predicate is null) { - var translation = _sqlExpressionFactory.Function( - "cardinality", - [array], - nullable: true, - argumentsPropagateNullability: TrueArrays[1], - typeof(int)); + switch (source) + { + case var _ when source.TryExtractArray(out var array, ignoreOrderings: true): + { + var translation = _sqlExpressionFactory.Function( + "cardinality", + [array], + nullable: true, + argumentsPropagateNullability: TrueArrays[1], + typeof(int)); + +#pragma warning disable EF1001 // SelectExpression constructors are currently internal + return source.Update( + new SelectExpression(translation, _queryCompilationContext.SqlAliasManager), + Expression.Convert( + new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int?)), + typeof(int))); +#pragma warning restore EF1001 + } + + case var _ when source.TryExtractJsonArray(out var jsonArray, out _, out _, ignoreOrderings: true): + { + var translation = _sqlExpressionFactory.Function( + jsonArray.TypeMapping!.StoreType switch + { + "jsonb" => "jsonb_array_length", + "json" => "json_array_length", + _ => throw new UnreachableException() + }, + [jsonArray], + nullable: true, + argumentsPropagateNullability: TrueArrays[1], + typeof(int)); #pragma warning disable EF1001 // SelectExpression constructors are currently internal - return source.Update( - new SelectExpression(translation, _queryCompilationContext.SqlAliasManager), - Expression.Convert( - new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int?)), - typeof(int))); + return source.Update( + new SelectExpression(translation, _queryCompilationContext.SqlAliasManager), + Expression.Convert( + new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(int?)), + typeof(int))); #pragma warning restore EF1001 + } + } } return base.TranslateCount(source, predicate); @@ -748,21 +883,41 @@ [new PgUnnestExpression(tableAlias, _sqlExpressionFactory.Add(array1, array2), " Expression index, bool returnDefault) { - // Simplify x.Array[1] => x.Array[1] (using the PG array subscript operator) instead of a subquery with LIMIT/OFFSET - // Note that we have unnest over multiranges, not just arrays - but multiranges don't support subscripting/slicing. - if (!returnDefault - && source.TryExtractArray(out var array, out var projectedColumn) - && TranslateExpression(index) is { } translatedIndex) + if (!returnDefault && TranslateExpression(index) is { } translatedIndex) { - // Note that PostgreSQL arrays are 1-based, so adjust the index. -#pragma warning disable EF1001 // SelectExpression constructors are currently internal - return source.UpdateQueryExpression( - new SelectExpression( - _sqlExpressionFactory.ArrayIndex( - array, - GenerateOneBasedIndexExpression(translatedIndex), projectedColumn.IsNullable), - _queryCompilationContext.SqlAliasManager)); -#pragma warning restore EF1001 +#pragma warning disable EF1001 // SelectExpression constructors are pubternal + switch (source) + { + // Simplify x.Array[1] => x.Array[1] (using the PG array subscript operator) instead of a subquery with LIMIT/OFFSET + // Note that we have unnest over multiranges, not just arrays - but multiranges don't support subscripting/slicing. + case var _ when source.TryExtractArray(out var array, out var projectedColumn): + { + return source.UpdateQueryExpression( + new SelectExpression( + _sqlExpressionFactory.ArrayIndex( + array, + // Note that PostgreSQL arrays are 1-based, so adjust the index. + GenerateOneBasedIndexExpression(translatedIndex), projectedColumn.IsNullable), + _queryCompilationContext.SqlAliasManager)); + } + + case var _ when source.TryExtractJsonArray(out var jsonArray, out var projectedElement, out var isElementNullable): + { + var (json, path) = jsonArray is JsonScalarExpression innerJsonScalarExpression + ? (innerJsonScalarExpression.Json, innerJsonScalarExpression.Path.Append(new(translatedIndex)).ToArray()) + : (jsonArray, [new(translatedIndex)]); + + var translation = new JsonScalarExpression( + json, + path, + projectedElement.Type, + projectedElement.TypeMapping, + isElementNullable); + + return source.UpdateQueryExpression(new SelectExpression(translation, _queryCompilationContext.SqlAliasManager)); + } + } +#pragma warning restore EF1001 // SelectExpression constructors are pubternal } return base.TranslateElementAtOrDefault(source, index, returnDefault); @@ -784,7 +939,7 @@ [new PgUnnestExpression(tableAlias, _sqlExpressionFactory.Add(array1, array2), " // Note that preprocessing normalizes FirstOrDefault(predicate) to Where(predicate).FirstOrDefault(), so the source's // select expression should already contain our predicate. if ((source.TryExtractArray(out var array, ignorePredicate: true) - || source.TryConvertValuesToArray(out array, ignorePredicate: true)) + || source.TryConvertToArray(out array, ignorePredicate: true)) && source.QueryExpression is SelectExpression { Tables: [{ Alias: var tableAlias }], Predicate: var translatedPredicate } && translatedPredicate is null ^ predicate is null) { diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlJsonTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlJsonTypeMapping.cs index 17eda324d..76397a13c 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlJsonTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlJsonTypeMapping.cs @@ -1,5 +1,6 @@ using System.Text; using System.Text.Json; +using Microsoft.EntityFrameworkCore.Storage.Json; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping; @@ -24,8 +25,13 @@ public class NpgsqlJsonTypeMapping : NpgsqlTypeMapping /// 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 NpgsqlJsonTypeMapping(string storeType, Type clrType) - : base(storeType, clrType, storeType == "jsonb" ? NpgsqlDbType.Jsonb : NpgsqlDbType.Json) + public NpgsqlJsonTypeMapping(string storeType, Type clrType, CoreTypeMapping? elementTypeMapping = null) + : base( + storeType, + clrType, + storeType == "jsonb" ? NpgsqlDbType.Jsonb : NpgsqlDbType.Json, + jsonValueReaderWriter: JsonStringReaderWriter.Instance, + elementTypeMapping: elementTypeMapping) { if (storeType != "json" && storeType != "jsonb") { diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlStructuralJsonTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlStructuralJsonTypeMapping.cs index 8fe503f11..eeb6413d5 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlStructuralJsonTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlStructuralJsonTypeMapping.cs @@ -35,7 +35,7 @@ private static readonly ConstructorInfo MemoryStreamConstructor /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public NpgsqlStructuralJsonTypeMapping(string storeType) - : base(storeType, typeof(JsonElement), dbType: null) + : base(storeType, typeof(JsonTypePlaceholder), dbType: null) { NpgsqlDbType = storeType switch { diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlTypeMapping.cs index ad48d39a8..6b9bd92dc 100644 --- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlTypeMapping.cs +++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlTypeMapping.cs @@ -20,8 +20,20 @@ public abstract class NpgsqlTypeMapping : RelationalTypeMapping, INpgsqlTypeMapp /// The CLR type to map. /// The database type used by Npgsql. /// Handles reading and writing JSON values for instances of the mapped type. - public NpgsqlTypeMapping(string storeType, Type clrType, NpgsqlDbType npgsqlDbType, JsonValueReaderWriter? jsonValueReaderWriter = null) - : base(storeType, clrType, jsonValueReaderWriter: jsonValueReaderWriter) + /// If this type mapping represents a primitive collection, this holds the element's type mapping. + public NpgsqlTypeMapping( + string storeType, + Type clrType, + NpgsqlDbType npgsqlDbType, + JsonValueReaderWriter? jsonValueReaderWriter = null, + CoreTypeMapping? elementTypeMapping = null) + : base( + new RelationalTypeMappingParameters( + new CoreTypeMappingParameters( + clrType, + jsonValueReaderWriter: jsonValueReaderWriter, + elementMapping: elementTypeMapping), + storeType)) { NpgsqlDbType = npgsqlDbType; } diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs index 7e457ec59..51c977c57 100644 --- a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs +++ b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Immutable; using System.Data; -using System.Data.Common; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.NetworkInformation; @@ -407,7 +406,12 @@ public NpgsqlTypeMappingSource( // Map arbitrary user POCOs to JSON if (storeTypeName is "jsonb" or "json") { - return new NpgsqlJsonTypeMapping(storeTypeName, clrType); + return FindCollectionMapping( + mappingInfo, + mappingInfo.ClrType, + providerType: null, + elementMapping: mappingInfo.CoreTypeMappingInfo.ElementTypeMapping) + ?? new NpgsqlJsonTypeMapping(storeTypeName, clrType); } return null; @@ -535,6 +539,22 @@ public NpgsqlTypeMappingSource( Type? modelType, Type? providerType, CoreTypeMapping? elementMapping) + => FindCollectionMapping(info.StoreTypeName, modelType, providerType, elementMapping); + + /// + /// 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 virtual RelationalTypeMapping? FindCollectionMapping( + string? storeType, + // Note that modelType is nullable (in the relational base signature it isn't) because of array scaffolding, i.e. we call + // FindCollectionMapping from our own FindMapping, where the clrType is null when scaffolding. + Type? modelClrType, + Type? providerClrType, + CoreTypeMapping? elementMapping) { if (elementMapping is not null and not RelationalTypeMapping) { @@ -544,169 +564,190 @@ public NpgsqlTypeMappingSource( Type concreteCollectionType; Type? elementType = null; - if (modelType is not null) + if (modelClrType is not null) { // We do GetElementType for multidimensional arrays - these don't implement generic IEnumerable<> - elementType = modelType.TryGetElementType(typeof(IEnumerable<>)) ?? modelType.GetElementType(); + elementType = modelClrType.TryGetElementType(typeof(IEnumerable<>)) ?? modelClrType.GetElementType(); // E.g. Newtonsoft.Json's JToken is enumerable over itself, exclude that scenario to avoid stack overflow. - if (elementType is null || elementType == modelType || modelType.GetGenericTypeImplementations(typeof(IDictionary<,>)).Any()) + if (elementType is null || elementType == modelClrType || modelClrType.GetGenericTypeImplementations(typeof(IDictionary<,>)).Any()) { return null; } } - var storeType = info.StoreTypeName; - if (storeType is null) + switch (storeType) { - if (modelType is null) + case null: { - return null; - } + if (modelClrType is null) + { + return null; + } + + // If no mapping was found for the element CLR type, there's no mapping for the array. + // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL + Check.DebugAssert(elementType is not null, "elementClrType is null"); + + var relationalElementMapping = elementMapping as RelationalTypeMapping ?? FindMapping(elementType); + if (relationalElementMapping is not { ElementTypeMapping: null }) + { + return null; + } + + // If the element type mapping is a range, default to return a multirange type mapping (if the PG version supports it). + // Otherwise an array over the range will be returned. + if (_supportsMultiranges) + { + if (relationalElementMapping is NpgsqlRangeTypeMapping rangeMapping) + { + var multirangeStoreType = rangeMapping.StoreType switch + { + "int4range" => "int4multirange", + "int8range" => "int8multirange", + "numrange" => "nummultirange", + "tsrange" => "tsmultirange", + "tstzrange" => "tstzmultirange", + "daterange" => "datemultirange", + + _ => throw new InvalidOperationException( + $"Cannot create multirange type mapping for range type '{rangeMapping.StoreType}'") + }; + + return new NpgsqlMultirangeTypeMapping(multirangeStoreType, modelClrType, rangeMapping); + } - // If no mapping was found for the element CLR type, there's no mapping for the array. - // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL - Check.DebugAssert(elementType is not null, "elementClrType is null"); + // TODO: This needs to move to the NodaTime plugin, but there's no FindCollectionMapping extension yet for plugins + if (relationalElementMapping.GetType() is + { Name: "IntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type1) + { + return (RelationalTypeMapping)Activator.CreateInstance( + type1.Assembly.GetType( + "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.IntervalMultirangeMapping")!, + modelClrType, + relationalElementMapping)!; + } - var relationalElementMapping = elementMapping as RelationalTypeMapping ?? FindMapping(elementType); - if (relationalElementMapping is not { ElementTypeMapping: null }) + if (relationalElementMapping.GetType() is + { Name: "DateIntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type2) + { + return (RelationalTypeMapping)Activator.CreateInstance( + type2.Assembly.GetType( + "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.DateIntervalMultirangeMapping")!, + modelClrType, + relationalElementMapping)!; + } + } + + // Not a multirange - map as a PG array type + concreteCollectionType = FindTypeToInstantiate(modelClrType, elementType); + + return (NpgsqlArrayTypeMapping)Activator.CreateInstance( + typeof(NpgsqlArrayTypeMapping<,,>).MakeGenericType(modelClrType, concreteCollectionType, elementType), + relationalElementMapping)!; + } + + case var _ when storeType.EndsWith("[]", StringComparison.Ordinal): { + // We have an array store type (either because we're reverse engineering or the user explicitly specified it) + var elementStoreType = storeType.Substring(0, storeType.Length - 2); + + // Note that we ignore the elementMapping argument here (but not in the CLR type-only path above). + // This is because the user-provided storeType for the array should take precedence over the element type mapping that gets + // calculated purely based on the element's CLR type in base.FindMappingWithConversion. + var relationalElementMapping = elementMapping as RelationalTypeMapping + ?? (elementType is null + ? FindMapping(elementStoreType) + : FindMapping(elementType, elementStoreType)); + if (relationalElementMapping is not { ElementTypeMapping: null }) + { + return null; + } + + // If no mapping was found for the element, there's no mapping for the array. + // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL + if (relationalElementMapping is not null and not NpgsqlArrayTypeMapping) + { + if (modelClrType is null) + { + // There's no model type - we're scaffolding purely from the store type. + elementType = relationalElementMapping.ClrType; + modelClrType = concreteCollectionType = typeof(List<>).MakeGenericType(elementType); + } + else + { + concreteCollectionType = FindTypeToInstantiate(modelClrType, elementType!); + Check.DebugAssert(elementType is not null, "elementType is null"); + } + + return (NpgsqlArrayTypeMapping)Activator.CreateInstance( + typeof(NpgsqlArrayTypeMapping<,,>).MakeGenericType(modelClrType, concreteCollectionType, elementType), + storeType, relationalElementMapping)!; + } + return null; } - // If the element type mapping is a range, default to return a multirange type mapping (if the PG version supports it). - // Otherwise an array over the range will be returned. - if (_supportsMultiranges) + case var _ when IsMultirange(storeType, out var rangeStoreType) && _supportsMultiranges: { - if (relationalElementMapping is NpgsqlRangeTypeMapping rangeMapping) + // Note that we ignore the elementMapping argument here (but not in the CLR type-only path above). + // This is because the user-provided storeType for the array should take precedence over the element type mapping that gets + // calculated purely based on the element's CLR type in base.FindMappingWithConversion. + var relationalElementMapping = elementType is null + ? FindMapping(rangeStoreType) + : FindMapping(elementType, rangeStoreType); + + // If no mapping was found for the element, there's no mapping for the array. + // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL + if (relationalElementMapping is NpgsqlRangeTypeMapping rangeMapping + // TODO: Why exclude if there's an element converter?? + && (relationalElementMapping.Converter is null || modelClrType is null || modelClrType.IsArrayOrGenericList())) { - var multirangeStoreType = rangeMapping.StoreType switch - { - "int4range" => "int4multirange", - "int8range" => "int8multirange", - "numrange" => "nummultirange", - "tsrange" => "tsmultirange", - "tstzrange" => "tstzmultirange", - "daterange" => "datemultirange", - - _ => throw new InvalidOperationException( - $"Cannot create multirange type mapping for range type '{rangeMapping.StoreType}'") - }; - - return new NpgsqlMultirangeTypeMapping(multirangeStoreType, modelType, rangeMapping); + return new NpgsqlMultirangeTypeMapping( + storeType, modelClrType ?? typeof(List<>).MakeGenericType(relationalElementMapping.ClrType), rangeMapping); } // TODO: This needs to move to the NodaTime plugin, but there's no FindCollectionMapping extension yet for plugins - if (relationalElementMapping.GetType() is + if (relationalElementMapping?.GetType() is { Name: "IntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type1) { return (RelationalTypeMapping)Activator.CreateInstance( type1.Assembly.GetType( "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.IntervalMultirangeMapping")!, - modelType, + modelClrType ?? relationalElementMapping.ClrType.MakeArrayType(), relationalElementMapping)!; } - if (relationalElementMapping.GetType() is + if (relationalElementMapping?.GetType() is { Name: "DateIntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type2) { return (RelationalTypeMapping)Activator.CreateInstance( type2.Assembly.GetType( "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.DateIntervalMultirangeMapping")!, - modelType, + modelClrType ?? relationalElementMapping.ClrType.MakeArrayType(), relationalElementMapping)!; } - } - // Not a multirange - map as a PG array type - concreteCollectionType = FindTypeToInstantiate(modelType, elementType); - - return (NpgsqlArrayTypeMapping)Activator.CreateInstance( - typeof(NpgsqlArrayTypeMapping<,,>).MakeGenericType(modelType, concreteCollectionType, elementType), - relationalElementMapping)!; - } - - if (storeType.EndsWith("[]", StringComparison.Ordinal)) - { - // We have an array store type (either because we're reverse engineering or the user explicitly specified it) - var elementStoreType = storeType.Substring(0, storeType.Length - 2); - - // Note that we ignore the elementMapping argument here (but not in the CLR type-only path above). - // This is because the user-provided storeType for the array should take precedence over the element type mapping that gets - // calculated purely based on the element's CLR type in base.FindMappingWithConversion. - var relationalElementMapping = elementMapping as RelationalTypeMapping - ?? (elementType is null - ? FindMapping(elementStoreType) - : FindMapping(elementType, elementStoreType)); - if (relationalElementMapping is not { ElementTypeMapping: null }) - { return null; } - // If no mapping was found for the element, there's no mapping for the array. - // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL - if (relationalElementMapping is not null and not NpgsqlArrayTypeMapping) - { - if (modelType is null) - { - // There's no model type - we're scaffolding purely from the store type. - elementType = relationalElementMapping.ClrType; - modelType = concreteCollectionType = typeof(List<>).MakeGenericType(elementType); - } - else - { - concreteCollectionType = FindTypeToInstantiate(modelType, elementType!); - Check.DebugAssert(elementType is not null, "elementType is null"); - } - - return (NpgsqlArrayTypeMapping)Activator.CreateInstance( - typeof(NpgsqlArrayTypeMapping<,,>).MakeGenericType(modelType, concreteCollectionType, elementType), - storeType, relationalElementMapping)!; - } - } - else if (IsMultirange(storeType, out var rangeStoreType) && _supportsMultiranges) - { - // Note that we ignore the elementMapping argument here (but not in the CLR type-only path above). - // This is because the user-provided storeType for the array should take precedence over the element type mapping that gets - // calculated purely based on the element's CLR type in base.FindMappingWithConversion. - var relationalElementMapping = elementType is null - ? FindMapping(rangeStoreType) - : FindMapping(elementType, rangeStoreType); - - // If no mapping was found for the element, there's no mapping for the array. - // Also, arrays of arrays aren't supported (as opposed to multidimensional arrays) by PostgreSQL - if (relationalElementMapping is NpgsqlRangeTypeMapping rangeMapping - // TODO: Why exclude if there's an element converter?? - && (relationalElementMapping.Converter is null || modelType is null || modelType.IsArrayOrGenericList())) - { - return new NpgsqlMultirangeTypeMapping( - storeType, modelType ?? typeof(List<>).MakeGenericType(relationalElementMapping.ClrType), rangeMapping); - } - - // TODO: This needs to move to the NodaTime plugin, but there's no FindCollectionMapping extension yet for plugins - if (relationalElementMapping?.GetType() is - { Name: "IntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type1) - { - return (RelationalTypeMapping)Activator.CreateInstance( - type1.Assembly.GetType( - "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.IntervalMultirangeMapping")!, - modelType ?? relationalElementMapping.ClrType.MakeArrayType(), - relationalElementMapping)!; - } - - if (relationalElementMapping?.GetType() is - { Name: "DateIntervalRangeMapping", Namespace: "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal" } type2) - { - return (RelationalTypeMapping)Activator.CreateInstance( - type2.Assembly.GetType( - "Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.DateIntervalMultirangeMapping")!, - modelType ?? relationalElementMapping.ClrType.MakeArrayType(), - relationalElementMapping)!; - } +#pragma warning disable EF1001 // SelectExpression constructors are pubternal + // This is a scalar collection mapped to JSON, which - unlike with other relational providers - is not the default: in PG we + // map to PG arrays instead. + // However, when scalar collections are nested inside a JSON document, they obviously have to be JSON-mapped. + // In addition, at least in theory users may decide to map to JSON instead of array even outside JSON documents. + case "jsonb" or "json" when modelClrType is not null: + return base.FindCollectionMapping( + new RelationalTypeMappingInfo(modelClrType, (RelationalTypeMapping?)elementMapping, storeType), + modelClrType, + providerClrType, + elementMapping); +#pragma warning restore EF1001 // SelectExpression constructors are pubternal + + default: + return null; } - return null; - static bool IsMultirange(string multiRangeStoreType, [NotNullWhen(true)] out string? rangeStoreType) { rangeStoreType = multiRangeStoreType switch @@ -958,6 +999,25 @@ static Type FindTypeToInstantiate(Type collectionType, Type elementType) return null; } + /// + public override RelationalTypeMapping? FindMapping(IProperty property) + { + var typeMapping = (RelationalTypeMapping?)base.FindMapping(property); + + if (typeMapping is NpgsqlArrayTypeMapping arrayMapping + && property.DeclaringType.IsMappedToJson()) + { + return FindCollectionMapping( + // TODO: Unfortunately GetContainerColumnType seems to return null at this point + property.DeclaringType.GetContainerColumnType() ?? "jsonb", + property.ClrType, + property.GetProviderClrType(), + arrayMapping.ElementTypeMapping); + } + + return typeMapping; + } + private static bool NameBasesUsesPrecision(ReadOnlySpan span) => span.ToString() switch { diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs index b5f903902..96616ab1d 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs @@ -212,7 +212,7 @@ SELECT COALESCE(sum(o0."Amount"), 0)::int """); } - [ConditionalTheory] // #3001 + [ConditionalTheory] // #3622 [MemberData(nameof(IsAsyncData))] public virtual async Task Update_with_primitive_collection_in_value_selector(bool async) { @@ -223,12 +223,12 @@ public virtual async Task Update_with_primitive_collection_in_value_selector(boo await ctx.SaveChangesAsync(); }); - await AssertUpdate( + await Assert.ThrowsAsync(() => AssertUpdate( async, contextFactory.CreateContext, ss => ss.EntitiesWithPrimitiveCollection, s => s.SetProperty(x => x.Tags, x => x.Tags.Append("another_tag")), - rowsAffectedCount: 1); + rowsAffectedCount: 1)); } protected class Context3001(DbContextOptions options) : DbContext(options) diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs index e65e91758..036179614 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs @@ -294,7 +294,7 @@ public override async Task Update_primitive_collection_to_constant() AssertExecuteUpdateSql( """ UPDATE "RootEntity" AS r -SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', to_jsonb(ARRAY[1,2,4]::integer[]::integer[])) +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', '[1,2,4]') """); } @@ -307,7 +307,7 @@ public override async Task Update_primitive_collection_to_parameter() @ints='?' (DbType = Object) UPDATE "RootEntity" AS r -SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', to_jsonb(@ints)) +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints}', @ints) """); } @@ -318,7 +318,7 @@ public override async Task Update_primitive_collection_to_another_collection() AssertExecuteUpdateSql( """ UPDATE "RootEntity" AS r -SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{OptionalNested,Ints}', to_jsonb((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality)))) +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{OptionalNested,Ints}', r."RequiredRelated" #> '{RequiredNested,Ints}') """); } @@ -326,7 +326,14 @@ public override async Task Update_inside_primitive_collection() { await base.Update_inside_primitive_collection(); - AssertExecuteUpdateSql(); + AssertExecuteUpdateSql( + """ +@p='?' (DbType = Int32) + +UPDATE "RootEntity" AS r +SET "RequiredRelated" = jsonb_set(r."RequiredRelated", '{Ints,1}', to_jsonb(@p)) +WHERE jsonb_array_length(r."RequiredRelated" -> 'Ints') >= 2 +"""); } #endregion Update primitive collection diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs index 6911164ec..44cbbfb17 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs @@ -16,7 +16,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -77,7 +77,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs index 88641ad57..d44cabd11 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonPrimitiveCollectionNpgsqlTest.cs @@ -11,7 +11,7 @@ public override async Task Count() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +WHERE jsonb_array_length(r."RequiredRelated" -> 'Ints') = 3 """); } @@ -23,7 +23,7 @@ public override async Task Index() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] = 1 +WHERE (CAST(r."RequiredRelated" #>> '{Ints,0}' AS integer)) = 1 """); } @@ -35,7 +35,7 @@ public override async Task Contains() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE 3 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +WHERE (r."RequiredRelated" -> 'Ints') @> to_jsonb(3) """); } @@ -47,7 +47,7 @@ public override async Task Any_predicate() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE 2 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +WHERE (r."RequiredRelated" -> 'Ints') @> to_jsonb(2) """); } @@ -59,7 +59,7 @@ public override async Task Nested_Count() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +WHERE jsonb_array_length(r."RequiredRelated" #> '{RequiredNested,Ints}') = 3 """); } @@ -70,12 +70,12 @@ public override async Task Select_Sum() AssertSql( """ SELECT ( - SELECT COALESCE(sum(i0.value), 0)::int - FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i0(value)) + SELECT COALESCE(sum(i0.element::int), 0)::int + FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS i0(element)) FROM "RootEntity" AS r WHERE ( - SELECT COALESCE(sum(i.value), 0)::int - FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i(value)) >= 6 + SELECT COALESCE(sum(i.element::int), 0)::int + FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS i(element)) >= 6 """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs index f7df1de3f..79d181db9 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonProjectionNpgsqlTest.cs @@ -196,7 +196,7 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -217,7 +217,7 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE @@ -235,7 +235,7 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."OptionalRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs index c8cf22cf4..fc3f43cb3 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs @@ -150,13 +150,16 @@ public override async Task Nested_collection_with_parameter() public override async Task Contains_with_inline() { - await base.Contains_with_inline(); - - // TODO: The following translation is sub-optimal: we should be using OPENSJON to extract elements of the collection as JSON elements (OPENJSON WITH JSON), - // and comparison those elements to a single entire JSON fragment on the other side (just like non-collection JSON comparison), rather than breaking the - // elements down to their columns and doing column-by-column comparison. See #32576. - AssertSql( - """ + // https://github.com/dotnet/efcore/issues/36837 + await Assert.ThrowsAsync(async () => + { + await base.Contains_with_inline(); + + // TODO: The following translation is sub-optimal: we should be using OPENSJON to extract elements of the collection as JSON elements (OPENJSON WITH JSON), + // and comparison those elements to a single entire JSON fragment on the other side (just like non-collection JSON comparison), rather than breaking the + // elements down to their columns and doing column-by-column comparison. See #32576. + AssertSql( + """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r WHERE EXISTS ( @@ -164,23 +167,27 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n - WHERE n."Id" = 1002 AND n."Int" = 8 AND n."Ints" = ARRAY[1,2,3]::integer[] AND n."Name" = 'Root1_RequiredRelated_NestedCollection_1' AND n."String" = 'foo') + WHERE n."Id" = 1002 AND n."Int" = 8 AND n."Ints" = '[1,2,3]' AND n."Name" = 'Root1_RequiredRelated_NestedCollection_1' AND n."String" = 'foo') """); + }); } public override async Task Contains_with_parameter() { - await base.Contains_with_parameter(); - - // TODO: The following translation is sub-optimal: we should be using OPENSJON to extract elements of the collection as JSON elements (OPENJSON WITH JSON), - // and comparison those elements to a single entire JSON fragment on the other side (just like non-collection JSON comparison), rather than breaking the - // elements down to their columns and doing column-by-column comparison. See #32576. - AssertSql( - """ + // https://github.com/dotnet/efcore/issues/36837 + await Assert.ThrowsAsync(async () => + { + await base.Contains_with_parameter(); + + // TODO: The following translation is sub-optimal: we should be using OPENSJON to extract elements of the collection as JSON elements (OPENJSON WITH JSON), + // and comparison those elements to a single entire JSON fragment on the other side (just like non-collection JSON comparison), rather than breaking the + // elements down to their columns and doing column-by-column comparison. See #32576. + AssertSql( + """ @entity_equality_nested_Id='?' (DbType = Int32) @entity_equality_nested_Int='?' (DbType = Int32) @entity_equality_nested_Ints='?' (DbType = Object) @@ -194,20 +201,24 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n WHERE n."Id" = @entity_equality_nested_Id AND n."Int" = @entity_equality_nested_Int AND n."Ints" = @entity_equality_nested_Ints AND n."Name" = @entity_equality_nested_Name AND n."String" = @entity_equality_nested_String) """); + }); } public override async Task Contains_with_operators_composed_on_the_collection() { - await base.Contains_with_operators_composed_on_the_collection(); + // https://github.com/dotnet/efcore/issues/36837 + await Assert.ThrowsAsync(async () => + { + await base.Contains_with_operators_composed_on_the_collection(); - AssertSql( - """ + AssertSql( + """ @get_Item_Int='?' (DbType = Int32) @entity_equality_get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Int='?' (DbType = Int32) @@ -222,20 +233,24 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n WHERE n."Int" > @get_Item_Int AND n."Id" = @entity_equality_get_Item_Id AND n."Int" = @entity_equality_get_Item_Int AND n."Ints" = @entity_equality_get_Item_Ints AND n."Name" = @entity_equality_get_Item_Name AND n."String" = @entity_equality_get_Item_String) """); + }); } public override async Task Contains_with_nested_and_composed_operators() { - await base.Contains_with_nested_and_composed_operators(); + // https://github.com/dotnet/efcore/issues/36837 + await Assert.ThrowsAsync(async () => + { + await base.Contains_with_nested_and_composed_operators(); - AssertSql( - """ + AssertSql( + """ @get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Id='?' (DbType = Int32) @entity_equality_get_Item_Int='?' (DbType = Int32) @@ -253,7 +268,7 @@ SELECT 1 FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -262,6 +277,7 @@ FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( )) WITH ORDINALITY AS r0 WHERE r0."Id" > @get_Item_Id AND r0."Id" = @entity_equality_get_Item_Id AND r0."Int" = @entity_equality_get_Item_Int AND r0."Ints" = @entity_equality_get_Item_Ints AND r0."Name" = @entity_equality_get_Item_Name AND r0."String" = @entity_equality_get_Item_String AND (r0."NestedCollection") = @entity_equality_get_Item_NestedCollection AND (r0."OptionalNested") = @entity_equality_get_Item_OptionalNested AND (r0."RequiredNested") = @entity_equality_get_Item_RequiredNested) """); + }); } #endregion Contains diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs index 9bc559554..aed87c791 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs @@ -425,7 +425,8 @@ public override async Task Update_primitive_collection_to_another_collection() public override async Task Update_inside_primitive_collection() { - await base.Update_inside_primitive_collection(); + // #3622, Support updating an element in an array with ExecuteUpdate + await Assert.ThrowsAsync(() => base.Update_inside_primitive_collection()); AssertExecuteUpdateSql(); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs index ca1e218c6..a5248fee6 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs @@ -19,7 +19,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -42,7 +42,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -63,7 +63,7 @@ SELECT r0."Int" FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -89,7 +89,7 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -115,7 +115,7 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -216,7 +216,7 @@ SELECT COALESCE(sum(r1."Int"), 0)::int FROM ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS r0 @@ -240,7 +240,7 @@ SELECT max(n."Int") FROM ROWS FROM (jsonb_to_recordset(r0."NestedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n)), 0)::int diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs index eb00c7d3a..5ebb66d56 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonPrimitiveCollectionNpgsqlTest.cs @@ -11,7 +11,7 @@ public override async Task Count() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +WHERE jsonb_array_length(r."RequiredRelated" -> 'Ints') = 3 """); } @@ -23,7 +23,7 @@ public override async Task Index() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] = 1 +WHERE (CAST(r."RequiredRelated" #>> '{Ints,0}' AS integer)) = 1 """); } @@ -35,7 +35,7 @@ public override async Task Contains() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE 3 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +WHERE (r."RequiredRelated" -> 'Ints') @> to_jsonb(3) """); } @@ -47,7 +47,7 @@ public override async Task Any_predicate() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE 2 = ANY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +WHERE (r."RequiredRelated" -> 'Ints') @> to_jsonb(2) """); } @@ -59,7 +59,7 @@ public override async Task Nested_Count() """ SELECT r."Id", r."Name", r."OptionalRelated", r."RelatedCollection", r."RequiredRelated" FROM "RootEntity" AS r -WHERE cardinality((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" #> '{RequiredNested,Ints}') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 3 +WHERE jsonb_array_length(r."RequiredRelated" #> '{RequiredNested,Ints}') = 3 """); } @@ -70,12 +70,12 @@ public override async Task Select_Sum() AssertSql( """ SELECT ( - SELECT COALESCE(sum(i0.value), 0)::int - FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i0(value)) + SELECT COALESCE(sum(i0.element::int), 0)::int + FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS i0(element)) FROM "RootEntity" AS r WHERE ( - SELECT COALESCE(sum(i.value), 0)::int - FROM unnest((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS i(value)) >= 6 + SELECT COALESCE(sum(i.element::int), 0)::int + FROM jsonb_array_elements_text(r."RequiredRelated" -> 'Ints') WITH ORDINALITY AS i(element)) >= 6 """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs index 6cbc69dfc..5060768d6 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonProjectionNpgsqlTest.cs @@ -228,7 +228,7 @@ public override async Task SelectMany_related_collection(QueryTrackingBehavior q JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RelatedCollection") AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text, "NestedCollection" jsonb, @@ -252,7 +252,7 @@ public override async Task SelectMany_nested_collection_on_required_related(Quer JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."RequiredRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE @@ -273,7 +273,7 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer JOIN LATERAL ROWS FROM (jsonb_to_recordset(r."OptionalRelated" -> 'NestedCollection') AS ( "Id" integer, "Int" integer, - "Ints" integer[], + "Ints" jsonb, "Name" text, "String" text )) WITH ORDINALITY AS n ON TRUE diff --git a/test/EFCore.PG.FunctionalTests/Query/JsonPocoQueryTest.cs b/test/EFCore.PG.FunctionalTests/Query/JsonPocoQueryTest.cs index feb4414e9..ffc1ae259 100644 --- a/test/EFCore.PG.FunctionalTests/Query/JsonPocoQueryTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/JsonPocoQueryTest.cs @@ -320,7 +320,7 @@ public void Array_toplevel() """ SELECT j."Id", j."Customer", j."ToplevelArray" FROM "JsonbEntities" AS j -WHERE j."ToplevelArray" ->> 1 = 'two' +WHERE (j."ToplevelArray" ->> 1) = 'two' LIMIT 2 """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/JsonQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/JsonQueryNpgsqlTest.cs index 5d2e42a4b..ce65575c4 100644 --- a/test/EFCore.PG.FunctionalTests/Query/JsonQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/JsonQueryNpgsqlTest.cs @@ -1004,11 +1004,11 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(j."OwnedReferenceRoot" -> 'OwnedCollectionBranch') AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o @@ -1033,11 +1033,11 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(o."OwnedCollectionBranch") AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o0) = 2) @@ -1055,9 +1055,9 @@ SELECT count(*)::int FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o) @@ -1117,9 +1117,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[] + "Numbers" jsonb )) WITH ORDINALITY AS o WHERE o."Name" = 'Foo' ) AS o0 ON TRUE @@ -1140,9 +1140,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o @@ -1168,11 +1168,11 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(o."OwnedCollectionBranch") AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o0 @@ -1197,7 +1197,7 @@ FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ("OwnedCollection LEFT JOIN LATERAL ROWS FROM (jsonb_to_recordset(o."OwnedCollectionBranch") AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "OwnedCollectionLeaf" jsonb, @@ -1221,9 +1221,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o @@ -1247,9 +1247,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o @@ -1296,9 +1296,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o @@ -1349,9 +1349,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o0 @@ -1364,11 +1364,11 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(o2."OwnedCollectionBranch") AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o3 @@ -1393,11 +1393,11 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedReferenceRoot" -> 'OwnedCollectionBranch') AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o @@ -1430,9 +1430,9 @@ public override async Task Json_collection_of_primitives_SelectMany(bool async) AssertSql( """ -SELECT n.value +SELECT n.element FROM "JsonEntitiesBasic" AS j -JOIN LATERAL unnest((ARRAY(SELECT CAST(element AS text) FROM jsonb_array_elements_text(j."OwnedReferenceRoot" -> 'Names') WITH ORDINALITY AS t(element) ORDER BY ordinality))) AS n(value) ON TRUE +JOIN LATERAL jsonb_array_elements_text(j."OwnedReferenceRoot" -> 'Names') WITH ORDINALITY AS n(element) ON TRUE """); } @@ -1444,7 +1444,7 @@ public override async Task Json_collection_of_primitives_index_used_in_predicate """ SELECT j."Id", j."EntityBasicId", j."Name", j."OwnedCollectionRoot", j."OwnedReferenceRoot" FROM "JsonEntitiesBasic" AS j -WHERE ((ARRAY(SELECT CAST(element AS text) FROM jsonb_array_elements_text(j."OwnedReferenceRoot" -> 'Names') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] = 'e1_r1' +WHERE (j."OwnedReferenceRoot" #>> '{Names,0}') = 'e1_r1' """); } @@ -1454,7 +1454,7 @@ public override async Task Json_collection_of_primitives_index_used_in_projectio AssertSql( """ -SELECT ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(j."OwnedReferenceRoot" #> '{OwnedReferenceBranch,Enums}') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] +SELECT CAST(j."OwnedReferenceRoot" #>> '{OwnedReferenceBranch,Enums,0}' AS integer) FROM "JsonEntitiesBasic" AS j ORDER BY j."Id" NULLS FIRST """); @@ -1468,7 +1468,7 @@ public override async Task Json_collection_of_primitives_index_used_in_orderby(b """ SELECT j."Id", j."EntityBasicId", j."Name", j."OwnedCollectionRoot", j."OwnedReferenceRoot" FROM "JsonEntitiesBasic" AS j -ORDER BY ((ARRAY(SELECT CAST(element AS integer) FROM jsonb_array_elements_text(j."OwnedReferenceRoot" -> 'Numbers') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[1] NULLS FIRST +ORDER BY CAST(j."OwnedReferenceRoot" #>> '{Numbers,0}' AS integer) NULLS FIRST """); } @@ -1480,7 +1480,7 @@ public override async Task Json_collection_of_primitives_contains_in_predicate(b """ SELECT j."Id", j."EntityBasicId", j."Name", j."OwnedCollectionRoot", j."OwnedReferenceRoot" FROM "JsonEntitiesBasic" AS j -WHERE 'e1_r1' = ANY ((ARRAY(SELECT CAST(element AS text) FROM jsonb_array_elements_text(j."OwnedReferenceRoot" -> 'Names') WITH ORDINALITY AS t(element) ORDER BY ordinality))) +WHERE (j."OwnedReferenceRoot" -> 'Names') @> to_jsonb('e1_r1'::text) """); } @@ -1497,11 +1497,11 @@ public override async Task Json_collection_index_with_parameter_Select_ElementAt FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot" #> ARRAY[@prm,'OwnedCollectionBranch']::text[]) AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer, "NullableEnum" integer, - "NullableEnums" integer[], + "NullableEnums" jsonb, "OwnedCollectionLeaf" jsonb, "OwnedReferenceLeaf" jsonb )) WITH ORDINALITY AS o @@ -1575,9 +1575,9 @@ LEFT JOIN LATERAL ( FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ( "Id" integer, "Name" text, - "Names" text[], + "Names" jsonb, "Number" integer, - "Numbers" integer[], + "Numbers" jsonb, "OwnedCollectionBranch" jsonb, "OwnedReferenceBranch" jsonb )) WITH ORDINALITY AS o @@ -2993,7 +2993,7 @@ FROM ROWS FROM (jsonb_to_recordset(j."OwnedCollectionRoot") AS ("OwnedCollection LEFT JOIN LATERAL ROWS FROM (jsonb_to_recordset(o."OwnedCollectionBranch") AS ( "Date" timestamp without time zone, "Enum" integer, - "Enums" integer[], + "Enums" jsonb, "Fraction" numeric(18,2), "Id" integer )) WITH ORDINALITY AS o0 ON TRUE diff --git a/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs index a6b9eebc8..5ea8bc486 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NonSharedPrimitiveCollectionsQueryNpgsqlTest.cs @@ -90,14 +90,14 @@ public override async Task Column_collection_inside_json_owned_entity() """ SELECT t."Id", t."Owned" FROM "TestOwner" AS t -WHERE cardinality((ARRAY(SELECT CAST(element AS text) FROM jsonb_array_elements_text(t."Owned" -> 'Strings') WITH ORDINALITY AS t(element) ORDER BY ordinality))) = 2 +WHERE jsonb_array_length(t."Owned" -> 'Strings') = 2 LIMIT 2 """, // """ SELECT t."Id", t."Owned" FROM "TestOwner" AS t -WHERE ((ARRAY(SELECT CAST(element AS text) FROM jsonb_array_elements_text(t."Owned" -> 'Strings') WITH ORDINALITY AS t(element) ORDER BY ordinality)))[2] = 'bar' +WHERE (t."Owned" #>> '{Strings,1}') = 'bar' LIMIT 2 """); } diff --git a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs index 3d586f384..a347e04c1 100644 --- a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs +++ b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs @@ -231,6 +231,17 @@ public void String_as_single_char_mapping_sets_NpgsqlDbType() Assert.Equal(NpgsqlDbType.Char, parameter.NpgsqlDbType); } + #region Array + + [Fact] + public void Primitive_collection() + { + var mapping = CreateTypeMappingSource().FindMapping(typeof(int[])); + Assert.IsType(mapping, exactMatch: false); + Assert.Equal("integer[]", mapping.StoreType); + Assert.Same(typeof(int[]), mapping.ClrType); + } + [Fact] public void Array_over_type_mapping_with_value_converter_by_clr_type_array() => Array_over_type_mapping_with_value_converter(CreateTypeMappingSource().FindMapping(typeof(LTree[])), typeof(LTree[])); @@ -268,6 +279,35 @@ private void Array_over_type_mapping_with_value_converter(CoreTypeMapping mappin s => Assert.Equal("bar", s)); } + #endregion Array + + #region JSON + + [Fact] + public void Json_structural() + { + var mapping = CreateTypeMappingSource().FindMapping(typeof(JsonTypePlaceholder)); + Assert.Equal("jsonb", mapping.StoreType); + Assert.Same(typeof(JsonTypePlaceholder), mapping.ClrType); + } + + [Fact] + public void Json_primitive_collection() + { + var mapping = CreateTypeMappingSource().FindMapping(typeof(int[]), "jsonb"); + Assert.Equal("jsonb", mapping.StoreType); + Assert.Same(typeof(IEnumerable), mapping.ClrType); + + var elementMapping = (RelationalTypeMapping)mapping.ElementTypeMapping; + Assert.NotNull(elementMapping); + Assert.Equal("integer", elementMapping.StoreType); + Assert.Same(typeof(int), elementMapping.ClrType); + } + + #endregion JSON + + #region Multirange + [Fact] public void Multirange_by_clr_type_across_pg_versions() { @@ -304,6 +344,8 @@ public void Multirange_by_store_type_across_pg_versions() Assert.Same(typeof(List>), mappingDefault.ClrType); } + #endregion Multirange + #nullable enable [Theory] [InlineData("integer", "integer", null, null, null, null)]