From 7f2538ed0d9d66877e666f9a5a6d37f12227f960 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 10 Feb 2026 09:02:34 +0100 Subject: [PATCH] Sync to EF 11.0.0-preview.1.26104.118 --- Directory.Build.props | 2 +- Directory.Packages.props | 14 +- NuGet.config | 4 +- global.json | 4 +- .../BuiltInDataTypesNpgsqlTest.cs | 237 --- .../NonSharedModelBulkUpdatesNpgsqlTest.cs | 30 +- .../NorthwindBulkUpdatesNpgsqlTest.cs | 132 +- ...tersInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + ...FiltersInheritanceBulkUpdatesNpgsqlTest.cs | 5 +- .../TPCInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + .../TPCInheritanceBulkUpdatesNpgsqlTest.cs | 5 +- ...tersInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + ...FiltersInheritanceBulkUpdatesNpgsqlTest.cs | 9 +- .../TPHInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + .../TPHInheritanceBulkUpdatesNpgsqlTest.cs | 9 +- ...tersInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + ...FiltersInheritanceBulkUpdatesNpgsqlTest.cs | 1 + .../TPTInheritanceBulkUpdatesNpgsqlFixture.cs | 1 + .../TPTInheritanceBulkUpdatesNpgsqlTest.cs | 1 + .../ConvertToProviderTypesNpgsqlTest.cs | 20 - .../CustomConvertersNpgsqlTest.cs | 24 - .../LazyLoadProxyNpgsqlTest.cs | 1474 +---------------- .../Query/AdHocComplexTypeQueryNpgsqlTest.cs | 12 +- .../Query/AdHocJsonQueryNpgsqlTest.cs | 2 + .../ComplexJsonBulkUpdateNpgsqlTest.cs | 32 +- .../ComplexJsonCollectionNpgsqlTest.cs | 14 +- .../ComplexJsonMiscellaneousNpgsqlTest.cs | 8 + ...ComplexJsonStructuralEqualityNpgsqlTest.cs | 44 +- ...mplexTableSplittingBulkUpdateNpgsqlTest.cs | 102 +- ...exTableSplittingMiscellaneousNpgsqlTest.cs | 11 + ...leSplittingStructuralEqualityNpgsqlTest.cs | 16 +- .../NavigationsCollectionNpgsqlTest.cs | 8 + .../NavigationsMiscellaneousNpgsqlTest.cs | 30 + .../OwnedJsonCollectionNpgsqlTest.cs | 12 + .../OwnedJsonMiscellaneousNpgsqlTest.cs | 13 + .../OwnedNavigationsCollectionNpgsqlTest.cs | 7 + ...OwnedNavigationsMiscellaneousNpgsqlTest.cs | 30 + ...edTableSplittingMiscellaneousNpgsqlTest.cs | 25 + .../Query/ComplexTypeQueryNpgsqlTest.cs | 8 +- .../Query/EntitySplittingQueryNpgsqlTest.cs | 13 + .../FiltersInheritanceQueryNpgsqlTest.cs | 2 +- ...TPCFiltersInheritanceQueryNpgsqlFixture.cs | 2 +- .../TPCFiltersInheritanceQueryNpgsqlTest.cs | 2 +- .../TPCGearsOfWarQueryNpgsqlFixture.cs | 2 +- .../TPCGearsOfWarQueryNpgsqlTest.cs | 2 +- .../TPCInheritanceJsonQueryNpgsqlFixture.cs | 10 + .../TPCInheritanceJsonQueryNpgsqlTest.cs | 179 ++ .../TPCInheritanceQueryNpgsqlFixture.cs | 2 +- .../TPCInheritanceQueryNpgsqlTest.cs | 768 +++++++++ ...nheritanceTableSplittingQueryNpgsqlTest.cs | 173 ++ .../TPCManyToManyNoTrackingQueryNpgsqlTest.cs | 2 +- .../TPCManyToManyQueryNpgsqlFixture.cs | 2 +- .../TPCManyToManyQueryNpgsqlTest.cs | 2 +- .../TPCRelationshipsQueryNpgsqlTest.cs | 2 +- ...TPHFiltersInheritanceQueryNpgsqlFixture.cs | 2 +- .../TPHInheritanceJsonQueryNpgsqlFixture.cs | 10 + .../TPHInheritanceJsonQueryNpgsqlTest.cs | 120 ++ .../TPHInheritanceQueryNpgsqlFixture.cs | 5 +- .../TPHInheritanceQueryNpgsqlTest.cs | 673 ++++++++ ...nheritanceTableSplittingQueryNpgsqlTest.cs | 123 ++ ...TPTFiltersInheritanceQueryNpgsqlFixture.cs | 7 + .../TPTFiltersInheritanceQueryNpgsqlTest.cs | 14 + .../TPTGearsOfWarQueryNpgsqlFixture.cs | 2 +- .../TPTGearsOfWarQueryNpgsqlTest.cs | 2 +- .../TPTInheritanceJsonQueryNpgsqlFixture.cs | 10 + .../TPTInheritanceJsonQueryNpgsqlTest.cs | 143 ++ .../TPTInheritanceQueryNpgsqlFixture.cs | 2 +- .../TPTInheritanceQueryNpgsqlTest.cs | 801 +++++++++ ...nheritanceTableSplittingQueryNpgsqlTest.cs | 146 ++ .../TPTManyToManyNoTrackingQueryNpgsqlTest.cs | 2 +- .../TPTManyToManyQueryNpgsqlFixture.cs | 2 +- .../TPTManyToManyQueryNpgsqlTest.cs | 2 +- .../TPTRelationshipsQueryNpgsqlTest.cs | 2 +- .../Query/NorthwindGroupByQueryNpgsqlTest.cs | 34 +- .../PrimitiveCollectionsQueryNpgsqlTest.cs | 297 +++- .../Query/TPCInheritanceQueryNpgsqlTest.cs | 8 - .../Query/TPHInheritanceQueryNpgsqlTest.cs | 4 - ...TPTFiltersInheritanceQueryNpgsqlFixture.cs | 7 - .../TPTFiltersInheritanceQueryNpgsqlTest.cs | 14 - .../Query/TPTInheritanceQueryNpgsqlTest.cs | 4 - .../RuntimeMigrationNpgsqlTest.cs | 32 + .../TestUtilities/NpgsqlDatabaseCleaner.cs | 34 +- .../NpgsqlDatabaseFacadeExtensions.cs | 4 +- .../TestUtilities/NpgsqlTestStore.cs | 4 +- .../Types/Miscellaneous/NpgsqlBoolTypeTest.cs | 31 +- .../Miscellaneous/NpgsqlByteArrayTypeTest.cs | 31 +- .../Types/Miscellaneous/NpgsqlGuidTypeTest.cs | 32 +- .../Miscellaneous/NpgsqlStringTypeTest.cs | 32 +- .../Types/Networking/NpgsqlInetTypeTest.cs | 31 +- .../Types/Networking/NpgsqlMacaddrTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlDecimalTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlDoubleTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlFloatTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlIntTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlLongTypeTest.cs | 32 +- .../Types/Numeric/NpgsqlShortTypeTest.cs | 31 +- .../Types/Temporal/NpgsqlDateOnlyTypeTest.cs | 31 +- .../Temporal/NpgsqlDateTimeOffsetTypeTest.cs | 32 +- .../NpgsqlDateTimeUnspecifiedTypeTest.cs | 32 +- .../Temporal/NpgsqlDateTimeUtcTypeTest.cs | 32 +- .../Types/Temporal/NpgsqlTimeOnlyTypeTest.cs | 32 +- .../Types/Temporal/NpgsqlTimeSpanTypeTest.cs | 31 +- .../UpdatesNpgsqlTest.cs | 2 +- 103 files changed, 4566 insertions(+), 2030 deletions(-) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCFiltersInheritanceQueryNpgsqlFixture.cs (71%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCFiltersInheritanceQueryNpgsqlTest.cs (76%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCGearsOfWarQueryNpgsqlFixture.cs (98%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCGearsOfWarQueryNpgsqlTest.cs (98%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlFixture.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCInheritanceQueryNpgsqlFixture.cs (75%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceTableSplittingQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCManyToManyNoTrackingQueryNpgsqlTest.cs (87%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCManyToManyQueryNpgsqlFixture.cs (95%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCManyToManyQueryNpgsqlTest.cs (86%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPCRelationshipsQueryNpgsqlTest.cs (90%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPHFiltersInheritanceQueryNpgsqlFixture.cs (70%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlFixture.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPHInheritanceQueryNpgsqlFixture.cs (87%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceTableSplittingQueryNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlFixture.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTGearsOfWarQueryNpgsqlFixture.cs (98%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTGearsOfWarQueryNpgsqlTest.cs (98%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlFixture.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTInheritanceQueryNpgsqlFixture.cs (75%) create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceTableSplittingQueryNpgsqlTest.cs rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTManyToManyNoTrackingQueryNpgsqlTest.cs (90%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTManyToManyQueryNpgsqlFixture.cs (95%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTManyToManyQueryNpgsqlTest.cs (89%) rename test/EFCore.PG.FunctionalTests/Query/{ => Inheritance}/TPTRelationshipsQueryNpgsqlTest.cs (91%) delete mode 100644 test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlTest.cs delete mode 100644 test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlTest.cs delete mode 100644 test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlFixture.cs delete mode 100644 test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlTest.cs delete mode 100644 test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlTest.cs create mode 100644 test/EFCore.PG.FunctionalTests/RuntimeMigrationNpgsqlTest.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1643ba419..1a8001cbd 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ 11.0.0-preview.1 - net10.0 + net11.0 latest enable true diff --git a/Directory.Packages.props b/Directory.Packages.props index d5d126668..d009e9dc6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,7 +1,7 @@ - 10.0.0 - 10.0.0 + 11.0.0-preview.1.26104.118 + 11.0.0-preview.1.26104.118 10.0.0 @@ -10,11 +10,11 @@ Dependencies on EF preview versions should be locked to a specific version (as provider-facing breaking changes are frequent). For released versions, depend on anything in the current major version to allow users to update to higher patch versions. --> - - - - - + + + + + diff --git a/NuGet.config b/NuGet.config index f95d7a9e9..98c370333 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,7 @@ - + @@ -18,7 +18,7 @@ - + diff --git a/global.json b/global.json index 6a6aeda3e..4ed6ab030 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "10.0.100", + "version": "11.0.100-preview.1.26104.118", "rollForward": "latestMinor", - "allowPrerelease": false + "allowPrerelease": true } } diff --git a/test/EFCore.PG.FunctionalTests/BuiltInDataTypesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BuiltInDataTypesNpgsqlTest.cs index 3154ab1a1..ff669fcb6 100644 --- a/test/EFCore.PG.FunctionalTests/BuiltInDataTypesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BuiltInDataTypesNpgsqlTest.cs @@ -719,212 +719,10 @@ private static void AssertNullMappedNullableDataTypes(MappedNullableDataTypes en Assert.Null(entity.Mood); } - public override async Task Can_query_with_null_parameters_using_any_nullable_data_type() - { - using (var context = CreateContext()) - { - context.Set().Add( - new BuiltInNullableDataTypes { Id = 711 }); - - Assert.Equal(1, await context.SaveChangesAsync()); - } - - using (var context = CreateContext()) - { - var entity = (await context.Set().Where(e => e.Id == 711).ToListAsync()).Single(); - - short? param1 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableInt16 == param1).ToListAsync()) - .Single()); - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && (long?)e.TestNullableInt16 == param1) - .ToListAsync()) - .Single()); - - int? param2 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableInt32 == param2).ToListAsync()) - .Single()); - - long? param3 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableInt64 == param3).ToListAsync()) - .Single()); - - double? param4 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableDouble == param4).ToListAsync()) - .Single()); - - decimal? param5 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableDecimal == param5).ToListAsync()) - .Single()); - - DateTime? param6 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableDateTime == param6).ToListAsync()) - .Single()); - - // We don't support DateTimeOffset - - TimeSpan? param8 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableTimeSpan == param8).ToListAsync()) - .Single()); - - float? param9 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableSingle == param9).ToListAsync()) - .Single()); - - bool? param10 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableBoolean == param10).ToListAsync()) - .Single()); - - // We don't support byte - - Enum64? param12 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.Enum64 == param12).ToListAsync()).Single()); - - Enum32? param13 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.Enum32 == param13).ToListAsync()).Single()); - - Enum16? param14 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.Enum16 == param14).ToListAsync()).Single()); - - Enum8? param15 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.Enum8 == param15).ToListAsync()).Single()); - - var entityType = context.Model.FindEntityType(typeof(BuiltInNullableDataTypes)); - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt16)) is not null) - { - ushort? param16 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableUnsignedInt16 == param16) - .ToListAsync()) - .Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt32)) is not null) - { - uint? param17 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableUnsignedInt32 == param17) - .ToListAsync()) - .Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableUnsignedInt64)) is not null) - { - ulong? param18 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableUnsignedInt64 == param18) - .ToListAsync()) - .Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableCharacter)) is not null) - { - char? param19 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableCharacter == param19) - .ToListAsync()) - .Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.TestNullableSignedByte)) is not null) - { - sbyte? param20 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.TestNullableSignedByte == param20) - .ToListAsync()) - .Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU64)) is not null) - { - EnumU64? param21 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.EnumU64 == param21).ToListAsync()).Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU32)) is not null) - { - EnumU32? param22 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.EnumU32 == param22).ToListAsync()).Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumU16)) is not null) - { - EnumU16? param23 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.EnumU16 == param23).ToListAsync()).Single()); - } - - if (entityType.FindProperty(nameof(BuiltInNullableDataTypes.EnumS8)) is not null) - { - EnumS8? param24 = null; - Assert.Same( - entity, - (await context.Set().Where(e => e.Id == 711 && e.EnumS8 == param24).ToListAsync()).Single()); - } - } - } - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_all_nullable_data_types_with_values_set_to_non_null() - => Task.CompletedTask; - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_non_nullable_backed_data_types() - => Task.CompletedTask; - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_nullable_backed_data_types() - => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] public override Task Can_insert_and_read_back_object_backed_data_types() => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_query_using_any_data_type_nullable_shadow() - => Task.CompletedTask; - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_query_using_any_data_type_shadow() - => Task.CompletedTask; - [ConditionalFact] public void Sum_Conversions() { @@ -1017,36 +815,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con // supported. modelBuilder.Entity().Property(b => b.TestDateTime) .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.TestNullableDateTime) - .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(nameof(BuiltInNullableDataTypes.TestNullableDateTime)) - .HasColumnType("timestamp without time zone"); modelBuilder.Entity().Property(b => b.DateTime) .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); // We don't support DateTimeOffset with non-zero offset, so we need to override the seeding data modelBuilder.Entity().Metadata.GetSeedData() .Single(t => (int)t[nameof(BuiltInDataTypes.Id)] == 13)[nameof(BuiltInDataTypes.TestDateTimeOffset)] = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.Zero); - modelBuilder.Entity().Metadata.GetSeedData() - .Single(t => (int)t[nameof(BuiltInDataTypes.Id)] == 13)[nameof(BuiltInNullableDataTypes.TestNullableDateTimeOffset)] - = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.Zero); - modelBuilder.Entity().Metadata.GetSeedData() .Single()[nameof(ObjectBackedDataTypes.DateTimeOffset)] = new DateTimeOffset(new DateTime(), TimeSpan.Zero); - modelBuilder.Entity().Metadata.GetSeedData() - .Single()[nameof(NullableBackedDataTypes.DateTimeOffset)] - = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.Zero); - - modelBuilder.Entity().Metadata.GetSeedData() - .Single()[nameof(NonNullableBackedDataTypes.DateTimeOffset)] = new DateTimeOffset(new DateTime(), TimeSpan.Zero); - modelBuilder.Entity( b => { @@ -1063,22 +842,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con //b.Ignore(dt => dt.EnumS8); }); - modelBuilder.Entity( - b => - { - b.Ignore(dt => dt.TestNullableUnsignedInt16); - b.Ignore(dt => dt.TestNullableUnsignedInt32); - b.Ignore(dt => dt.TestNullableUnsignedInt64); - b.Ignore(dt => dt.TestNullableCharacter); - b.Ignore(dt => dt.TestNullableSignedByte); - b.Ignore(dt => dt.TestNullableDateTimeOffset); - b.Ignore(dt => dt.TestNullableByte); - //b.Ignore(dt => dt.EnumU16); - //b.Ignore(dt => dt.EnumU32); - //b.Ignore(dt => dt.EnumU64); - //b.Ignore(dt => dt.EnumS8); - }); - modelBuilder.Entity( b => { diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs index 96616ab1d..98f4a1f9c 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesNpgsqlTest.cs @@ -5,9 +5,19 @@ public class NonSharedModelBulkUpdatesNpgsqlTest(NonSharedFixture fixture) : Non protected override ITestStoreFactory TestStoreFactory => NpgsqlTestStoreFactory.Instance; - [ConditionalFact] - public virtual void Check_all_tests_overridden() - => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Update_complex_type_property_with_view_mapping(bool async) + { + await base.Update_complex_type_property_with_view_mapping(async); + + AssertSql( + """ +@p='6' + +UPDATE "Blogs" AS b +SET "ComplexThing_Prop1" = @p +"""); + } public override async Task Delete_aggregate_root_when_eager_loaded_owned_collection(bool async) { @@ -270,7 +280,15 @@ public override async Task Update_complex_type_with_view_mapping(bool async) await base.Update_complex_type_with_view_mapping(async); // #34706 - AssertSql(); + AssertSql( + """ +@complex_type_p_Prop1='3' (Nullable = true) +@complex_type_p_Prop2='4' (Nullable = true) + +UPDATE "Blogs" AS b +SET "ComplexThing_Prop1" = @complex_type_p_Prop1, + "ComplexThing_Prop2" = @complex_type_p_Prop2 +"""); } private void AssertSql(params string[] expected) @@ -278,4 +296,8 @@ private void AssertSql(params string[] expected) private void AssertExecuteUpdateSql(params string[] expected) => TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); } diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesNpgsqlTest.cs index 30494430c..467bb4390 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesNpgsqlTest.cs @@ -256,8 +256,8 @@ public override async Task Delete_Where_Skip_Take_Skip_Take_causing_subquery(boo AssertSql( """ @p='100' -@p2='5' -@p1='20' +@p3='5' +@p2='20' DELETE FROM "Order Details" AS o WHERE EXISTS ( @@ -270,7 +270,7 @@ SELECT 1 WHERE o1."OrderID" < 10300 LIMIT @p OFFSET @p ) AS o0 - LIMIT @p2 OFFSET @p1 + LIMIT @p3 OFFSET @p2 ) AS o2 WHERE o2."OrderID" = o."OrderID" AND o2."ProductID" = o."ProductID") """); @@ -495,7 +495,7 @@ public override async Task Delete_with_join(bool async) AssertSql( """ -@p0='100' +@p1='100' @p='0' DELETE FROM "Order Details" AS o @@ -504,7 +504,7 @@ SELECT o0."OrderID" FROM "Orders" AS o0 WHERE o0."OrderID" < 10300 ORDER BY o0."OrderID" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS o1 WHERE o."OrderID" = o1."OrderID" """); @@ -516,7 +516,7 @@ public override async Task Delete_with_LeftJoin(bool async) AssertSql( """ -@p0='100' +@p1='100' @p='0' DELETE FROM "Order Details" AS o @@ -528,7 +528,7 @@ SELECT o2."OrderID" FROM "Orders" AS o2 WHERE o2."OrderID" < 10300 ORDER BY o2."OrderID" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS o1 ON o0."OrderID" = o1."OrderID" WHERE o0."OrderID" < 10276 AND o0."OrderID" = o."OrderID" AND o0."ProductID" = o."ProductID") """); @@ -540,7 +540,7 @@ public override async Task Delete_with_LeftJoin_via_flattened_GroupJoin(bool asy AssertSql( """ -@p0='100' +@p1='100' @p='0' DELETE FROM "Order Details" AS o @@ -552,7 +552,7 @@ SELECT o2."OrderID" FROM "Orders" AS o2 WHERE o2."OrderID" < 10300 ORDER BY o2."OrderID" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS o1 ON o0."OrderID" = o1."OrderID" WHERE o0."OrderID" < 10276 AND o0."OrderID" = o."OrderID" AND o0."ProductID" = o."ProductID") """); @@ -627,7 +627,7 @@ public override async Task Delete_with_RightJoin(bool async) AssertSql( """ -@p0='100' +@p1='100' @p='0' DELETE FROM "Order Details" AS o @@ -639,7 +639,7 @@ SELECT o2."OrderID" FROM "Orders" AS o2 WHERE o2."OrderID" < 10300 ORDER BY o2."OrderID" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS o1 ON o0."OrderID" = o1."OrderID" WHERE o0."OrderID" < 10276 AND o0."OrderID" = o."OrderID" AND o0."ProductID" = o."ProductID") """); @@ -817,11 +817,11 @@ public override async Task Update_Where_OrderBy_Skip_set_constant(bool async) AssertExecuteUpdateSql( """ -@p0='Updated' +@p1='Updated' @p='4' UPDATE "Customers" AS c0 -SET "ContactName" = @p0 +SET "ContactName" = @p1 FROM ( SELECT c."CustomerID" FROM "Customers" AS c @@ -839,11 +839,11 @@ public override async Task Update_Where_OrderBy_Take_set_constant(bool async) AssertExecuteUpdateSql( """ -@p0='Updated' +@p1='Updated' @p='4' UPDATE "Customers" AS c0 -SET "ContactName" = @p0 +SET "ContactName" = @p1 FROM ( SELECT c."CustomerID" FROM "Customers" AS c @@ -861,18 +861,18 @@ public override async Task Update_Where_OrderBy_Skip_Take_set_constant(bool asyn AssertExecuteUpdateSql( """ -@p1='Updated' -@p0='4' +@p2='Updated' +@p1='4' @p='2' UPDATE "Customers" AS c0 -SET "ContactName" = @p1 +SET "ContactName" = @p2 FROM ( SELECT c."CustomerID" FROM "Customers" AS c WHERE c."CustomerID" LIKE 'F%' ORDER BY c."City" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS c1 WHERE c0."CustomerID" = c1."CustomerID" """); @@ -884,12 +884,12 @@ public override async Task Update_Where_OrderBy_Skip_Take_Skip_Take_set_constant AssertExecuteUpdateSql( """ -@p3='Updated' -@p0='6' +@p4='Updated' +@p1='6' @p='2' UPDATE "Customers" AS c1 -SET "ContactName" = @p3 +SET "ContactName" = @p4 FROM ( SELECT c0."CustomerID" FROM ( @@ -897,7 +897,7 @@ SELECT c0."CustomerID" FROM "Customers" AS c WHERE c."CustomerID" LIKE 'F%' ORDER BY c."City" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS c0 ORDER BY c0."City" NULLS FIRST LIMIT @p OFFSET @p @@ -1611,6 +1611,92 @@ await AssertUpdate( """); } + + public override async Task Update_set_constant_TagWith_null(bool async) + { + await base.Update_set_constant_TagWith_null(async); + + AssertSql( + """ +-- MyUpdate + +SELECT c."CustomerID", c."Address", c."City", c."CompanyName", c."ContactName", c."ContactTitle", c."Country", c."Fax", c."Phone", c."PostalCode", c."Region" +FROM "Customers" AS c +""", + // + """ +-- MyUpdate + +UPDATE "Customers" AS c +SET "ContactName" = NULL +""", + // + """ +-- MyUpdate + +SELECT c."CustomerID", c."Address", c."City", c."CompanyName", c."ContactName", c."ContactTitle", c."Country", c."Fax", c."Phone", c."PostalCode", c."Region" +FROM "Customers" AS c +"""); + } + + + public override async Task Update_with_PK_pushdown_and_join_and_multiple_setters(bool async) + { + await base.Update_with_PK_pushdown_and_join_and_multiple_setters(async); + + AssertSql( + """ +@p='1' + +SELECT o1."OrderID", o1."ProductID", o1."Discount", o1."Quantity", o1."UnitPrice" +FROM ( + SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice" + FROM "Order Details" AS o + ORDER BY o."OrderID" NULLS FIRST + OFFSET @p +) AS o1 +INNER JOIN "Orders" AS o0 ON o1."OrderID" = o0."OrderID" +WHERE o0."CustomerID" = 'ALFKI' +ORDER BY o1."OrderID" NULLS FIRST +""", + // + """ +@p='1' +@p2='10' + +UPDATE "Order Details" AS o2 +SET "Quantity" = @p::smallint, + "UnitPrice" = @p2 +FROM ( + SELECT o1."OrderID", o1."ProductID" + FROM ( + SELECT o."OrderID", o."ProductID" + FROM "Order Details" AS o + ORDER BY o."OrderID" NULLS FIRST + OFFSET @p + ) AS o1 + INNER JOIN "Orders" AS o0 ON o1."OrderID" = o0."OrderID" + WHERE o0."CustomerID" = 'ALFKI' +) AS s +WHERE o2."OrderID" = s."OrderID" AND o2."ProductID" = s."ProductID" +""", + // + """ +@p='1' + +SELECT o1."OrderID", o1."ProductID", o1."Discount", o1."Quantity", o1."UnitPrice" +FROM ( + SELECT o."OrderID", o."ProductID", o."Discount", o."Quantity", o."UnitPrice" + FROM "Order Details" AS o + ORDER BY o."OrderID" NULLS FIRST + OFFSET @p +) AS o1 +INNER JOIN "Orders" AS o0 ON o1."OrderID" = o0."OrderID" +WHERE o0."CustomerID" = 'ALFKI' +ORDER BY o1."OrderID" NULLS FIRST +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlFixture.cs index 9aaf4e69d..6035fa2a5 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPCFiltersInheritanceBulkUpdatesNpgsqlFixture : TPCInheritanceBulkUpdatesNpgsqlFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlTest.cs index 02f702961..8dbbbf321 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPCFiltersInheritanceBulkUpdatesNpgsqlTest( @@ -174,11 +175,11 @@ public override async Task Update_base_and_derived_types(bool async) AssertExecuteUpdateSql( """ @p='Kiwi' -@p0='0' +@p1='0' UPDATE "Kiwi" AS k SET "Name" = @p, - "FoundOn" = @p0 + "FoundOn" = @p1 WHERE k."CountryId" = 1 """); } diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlFixture.cs index 1d2b2b8f1..faa0cdda1 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPCInheritanceBulkUpdatesNpgsqlFixture : TPCInheritanceBulkUpdatesFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlTest.cs index d66fdad9a..46291a7a3 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPCInheritanceBulkUpdatesNpgsqlTest( @@ -172,11 +173,11 @@ public override async Task Update_base_and_derived_types(bool async) AssertExecuteUpdateSql( """ @p='Kiwi' -@p0='0' +@p1='0' UPDATE "Kiwi" AS k SET "Name" = @p, - "FoundOn" = @p0 + "FoundOn" = @p1 """); } diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlFixture.cs index 281e76cfe..24550e11d 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPHFiltersInheritanceBulkUpdatesNpgsqlFixture : TPHInheritanceBulkUpdatesNpgsqlFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlTest.cs index f963c3044..1786391cd 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHFiltersInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPHFiltersInheritanceBulkUpdatesNpgsqlTest( @@ -132,7 +133,7 @@ public override async Task Delete_where_hierarchy_subquery(bool async) AssertSql( """ -@p0='3' +@p1='3' @p='0' DELETE FROM "Animals" AS a @@ -141,7 +142,7 @@ SELECT a0."Id" FROM "Animals" AS a0 WHERE a0."CountryId" = 1 AND a0."Name" = 'Great spotted kiwi' ORDER BY a0."Name" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) """); } @@ -188,11 +189,11 @@ public override async Task Update_base_and_derived_types(bool async) AssertExecuteUpdateSql( """ @p='Kiwi' -@p0='0' +@p1='0' UPDATE "Animals" AS a SET "Name" = @p, - "FoundOn" = @p0 + "FoundOn" = @p1 WHERE a."Discriminator" = 'Kiwi' AND a."CountryId" = 1 """); } diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlFixture.cs index d783d64d3..cd3235e30 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.InheritanceModel; +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPHInheritanceBulkUpdatesNpgsqlFixture : TPHInheritanceBulkUpdatesFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlTest.cs index 3b2254152..debaa5835 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPHInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPHInheritanceBulkUpdatesNpgsqlTest( @@ -96,7 +97,7 @@ public override async Task Delete_where_hierarchy_subquery(bool async) AssertSql( """ -@p0='3' +@p1='3' @p='0' DELETE FROM "Animals" AS a @@ -105,7 +106,7 @@ SELECT a0."Id" FROM "Animals" AS a0 WHERE a0."Name" = 'Great spotted kiwi' ORDER BY a0."Name" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) """); } @@ -198,11 +199,11 @@ public override async Task Update_base_and_derived_types(bool async) AssertExecuteUpdateSql( """ @p='Kiwi' -@p0='0' +@p1='0' UPDATE "Animals" AS a SET "Name" = @p, - "FoundOn" = @p0 + "FoundOn" = @p1 WHERE a."Discriminator" = 'Kiwi' """); } diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlFixture.cs index 4069a3542..efdd4d349 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPTFiltersInheritanceBulkUpdatesNpgsqlFixture : TPTInheritanceBulkUpdatesNpgsqlFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlTest.cs index 9da3e5dfb..0517c42ec 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPTFiltersInheritanceBulkUpdatesSqlServerTest( diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlFixture.cs index 67e773802..b614797be 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlFixture.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPTInheritanceBulkUpdatesNpgsqlFixture : TPTInheritanceBulkUpdatesFixture diff --git a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlTest.cs index 5c1b8dcc0..b6ffe9302 100644 --- a/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesNpgsqlTest.cs @@ -1,3 +1,4 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates.Inheritance; namespace Microsoft.EntityFrameworkCore.BulkUpdates; public class TPTInheritanceBulkUpdatesNpgsqlTest( diff --git a/test/EFCore.PG.FunctionalTests/ConvertToProviderTypesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/ConvertToProviderTypesNpgsqlTest.cs index 0d69d9173..9196dc66f 100644 --- a/test/EFCore.PG.FunctionalTests/ConvertToProviderTypesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/ConvertToProviderTypesNpgsqlTest.cs @@ -49,14 +49,6 @@ public ConvertToProviderTypesNpgsqlTest(ConvertToProviderTypesNpgsqlFixture fixt // } // } - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_non_nullable_backed_data_types() - => Task.CompletedTask; - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_nullable_backed_data_types() - => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] public override Task Can_insert_and_read_back_object_backed_data_types() => Task.CompletedTask; @@ -101,23 +93,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con // supported. modelBuilder.Entity().Property(b => b.DateTime) .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); // We don't support DateTimeOffset with non-zero offset, so we need to override the seeding data var objectBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); objectBackedDataTypes[nameof(ObjectBackedDataTypes.DateTimeOffset)] = new DateTimeOffset(new DateTime(), TimeSpan.Zero); - - var nullableBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); - nullableBackedDataTypes[nameof(NullableBackedDataTypes.DateTimeOffset)] - = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.Zero); - - var nonNullableBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); - nonNullableBackedDataTypes[nameof(NonNullableBackedDataTypes.DateTimeOffset)] - = new DateTimeOffset(new DateTime(), TimeSpan.Zero); } } } diff --git a/test/EFCore.PG.FunctionalTests/CustomConvertersNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/CustomConvertersNpgsqlTest.cs index 15502c010..e7571d81c 100644 --- a/test/EFCore.PG.FunctionalTests/CustomConvertersNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/CustomConvertersNpgsqlTest.cs @@ -7,22 +7,10 @@ public class CustomConvertersNpgsqlTest(CustomConvertersNpgsqlTest.CustomConvert public override Task Can_insert_and_read_back_with_case_insensitive_string_key() => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_non_nullable_backed_data_types() - => Task.CompletedTask; - - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_insert_and_read_back_nullable_backed_data_types() - => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] public override Task Can_insert_and_read_back_object_backed_data_types() => Task.CompletedTask; - [ConditionalFact(Skip = "DateTimeOffset with non-zero offset, https://github.com/dotnet/efcore/issues/26068")] - public override Task Can_query_using_any_data_type_nullable_shadow() - => Task.CompletedTask; - public override void Value_conversion_on_enum_collection_contains() => Assert.Contains( CoreStrings.TranslationFailed("").Substring(47), @@ -65,23 +53,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con // supported. modelBuilder.Entity().Property(b => b.DateTime) .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); - modelBuilder.Entity().Property(b => b.DateTime) - .HasColumnType("timestamp without time zone"); // We don't support DateTimeOffset with non-zero offset, so we need to override the seeding data var objectBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); objectBackedDataTypes[nameof(ObjectBackedDataTypes.DateTimeOffset)] = new DateTimeOffset(new DateTime(), TimeSpan.Zero); - - var nullableBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); - nullableBackedDataTypes[nameof(NullableBackedDataTypes.DateTimeOffset)] - = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.Zero); - - var nonNullableBackedDataTypes = modelBuilder.Entity().Metadata.GetSeedData().Single(); - nonNullableBackedDataTypes[nameof(NonNullableBackedDataTypes.DateTimeOffset)] - = new DateTimeOffset(new DateTime(), TimeSpan.Zero); } } } diff --git a/test/EFCore.PG.FunctionalTests/LazyLoadProxyNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/LazyLoadProxyNpgsqlTest.cs index affdd7bf3..0f8199dd7 100644 --- a/test/EFCore.PG.FunctionalTests/LazyLoadProxyNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/LazyLoadProxyNpgsqlTest.cs @@ -1,4 +1,6 @@ -namespace Microsoft.EntityFrameworkCore; +using Xunit.Sdk; + +namespace Microsoft.EntityFrameworkCore; // ReSharper disable once UnusedMember.Global public class LazyLoadProxyNpgsqlTest : LazyLoadProxyRelationalTestBase @@ -9,6 +11,10 @@ public LazyLoadProxyNpgsqlTest(LoadNpgsqlFixture fixture) Fixture.TestSqlLoggerFactory.Clear(); } + // TODO: Test is problematic and brittle + public override void Can_serialize_proxies_to_JSON() + => Assert.Throws(base.Can_serialize_proxies_to_JSON); + [ConditionalFact] // Requires MARS public override void Top_level_projection_track_entities_before_passing_to_client_method() { } @@ -25,1472 +31,6 @@ protected override void RecordLog() // ReSharper disable once UnusedAutoPropertyAccessor.Local private string Sql { get; set; } = null!; - #region Expected JSON override - - // TODO: Tiny discrepancy in decimal representation (Charge: 1.0 instead of 1.00) - protected override string SerializedBlogs2 - => """ -{ - "$id": "1", - "$values": [ - { - "$id": "2", - "Id": 1, - "Writer": { - "$id": "3", - "FirstName": "firstNameWriter0", - "LastName": "lastNameWriter0", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "4", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "5", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "6", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "7", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "8", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "9", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "10", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Reader": { - "$id": "11", - "FirstName": "firstNameReader0", - "LastName": "lastNameReader0", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "12", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "13", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "14", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "15", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "16", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "17", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "18", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Host": { - "$id": "19", - "HostName": "127.0.0.1", - "Rating": 0, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "20", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "21", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "22", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "23", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "24", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "25", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "26", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "27", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "28", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "29", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "30", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "31", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "32", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "33", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - { - "$id": "34", - "Id": 2, - "Writer": { - "$id": "35", - "FirstName": "firstNameWriter1", - "LastName": "lastNameWriter1", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "36", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "37", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "38", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "39", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "40", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "41", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "42", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Reader": { - "$id": "43", - "FirstName": "firstNameReader1", - "LastName": "lastNameReader1", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "44", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "45", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "46", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "47", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "48", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "49", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "50", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Host": { - "$id": "51", - "HostName": "127.0.0.2", - "Rating": 0, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "52", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "53", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "54", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "55", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "56", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "57", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "58", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "59", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "60", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "61", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "62", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "63", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "64", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "65", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - { - "$id": "66", - "Id": 3, - "Writer": { - "$id": "67", - "FirstName": "firstNameWriter2", - "LastName": "lastNameWriter2", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "68", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "69", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "70", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "71", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "72", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "73", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "74", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Reader": { - "$id": "75", - "FirstName": "firstNameReader2", - "LastName": "lastNameReader2", - "Alive": false, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "76", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "77", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "78", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "79", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "80", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "81", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "82", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Host": { - "$id": "83", - "HostName": "127.0.0.3", - "Rating": 0, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "84", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "85", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "86", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "87", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "88", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "89", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "90", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "91", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "92", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "93", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "$id": "94", - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "$id": "95", - "Name": "M1", - "Rating": 7, - "Tag": { - "$id": "96", - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "$id": "97", - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - } - } - ] -} -"""; - - protected override string SerializedBlogs1 - => """ -[ - { - "Writer": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameWriter0", - "LastName": "lastNameWriter0", - "Alive": false - }, - "Reader": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameReader0", - "LastName": "lastNameReader0", - "Alive": false - }, - "Host": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "HostName": "127.0.0.1", - "Rating": 0.0 - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Id": 1 - }, - { - "Writer": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameWriter1", - "LastName": "lastNameWriter1", - "Alive": false - }, - "Reader": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameReader1", - "LastName": "lastNameReader1", - "Alive": false - }, - "Host": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "HostName": "127.0.0.2", - "Rating": 0.0 - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Id": 2 - }, - { - "Writer": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameWriter2", - "LastName": "lastNameWriter2", - "Alive": false - }, - "Reader": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "FirstName": "firstNameReader2", - "LastName": "lastNameReader2", - "Alive": false - }, - "Host": { - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "HostName": "127.0.0.3", - "Rating": 0.0 - }, - "Culture": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Milk": { - "Species": "S1", - "Subspecies": null, - "Rating": 8, - "Validation": false, - "Manufacturer": { - "Name": "M1", - "Rating": 7, - "Tag": { - "Text": "Ta2" - }, - "Tog": { - "Text": "To2" - } - }, - "License": { - "Title": "Ti1", - "Charge": 1.0, - "Tag": { - "Text": "Ta1" - }, - "Tog": { - "Text": "To1" - } - } - }, - "Id": 3 - } -] -"""; - - #endregion Expected JSON override - public class LoadNpgsqlFixture : LoadRelationalFixtureBase { public TestSqlLoggerFactory TestSqlLoggerFactory diff --git a/test/EFCore.PG.FunctionalTests/Query/AdHocComplexTypeQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/AdHocComplexTypeQueryNpgsqlTest.cs index 83cc8d30e..30f940e83 100644 --- a/test/EFCore.PG.FunctionalTests/Query/AdHocComplexTypeQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/AdHocComplexTypeQueryNpgsqlTest.cs @@ -1,11 +1,7 @@ namespace Microsoft.EntityFrameworkCore.Query; -public class AdHocComplexTypeQueryNpgsqlTest(NonSharedFixture fixture) : AdHocComplexTypeQueryTestBase(fixture) +public class AdHocComplexTypeQueryNpgsqlTest(NonSharedFixture fixture) : AdHocComplexTypeQueryRelationalTestBase(fixture) { - // Test is SQL Server-specific and being removed, https://github.com/dotnet/efcore/pull/37177 - public override Task Complex_type_equality_with_non_default_type_mapping() - => Task.CompletedTask; - public override async Task Complex_type_equals_parameter_with_nested_types_with_property_of_same_name() { await base.Complex_type_equals_parameter_with_nested_types_with_property_of_same_name(); @@ -23,12 +19,6 @@ LIMIT 2 """); } - protected TestSqlLoggerFactory TestSqlLoggerFactory - => (TestSqlLoggerFactory)ListLoggerFactory; - - protected void AssertSql(params string[] expected) - => TestSqlLoggerFactory.AssertBaseline(expected); - protected override ITestStoreFactory TestStoreFactory => NpgsqlTestStoreFactory.Instance; } diff --git a/test/EFCore.PG.FunctionalTests/Query/AdHocJsonQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/AdHocJsonQueryNpgsqlTest.cs index e613d913c..ffeb482f7 100644 --- a/test/EFCore.PG.FunctionalTests/Query/AdHocJsonQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/AdHocJsonQueryNpgsqlTest.cs @@ -1,5 +1,7 @@ using Xunit.Sdk; +#pragma warning disable EF8001 // ToJson on owned entities is obsolete + namespace Microsoft.EntityFrameworkCore.Query; #nullable disable diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs index baba29db4..5401fc868 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs @@ -13,7 +13,7 @@ public override async Task Delete_entity_with_associations() AssertSql( """ -@deletableEntity_Name='?' +@deletableEntity_Name='Root3_With_different_values' DELETE FROM "RootEntity" AS r WHERE r."Name" = @deletableEntity_Name @@ -44,7 +44,7 @@ public override async Task Update_property_inside_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{String}', to_jsonb(@p)) @@ -69,7 +69,7 @@ public override async Task Update_property_inside_nested_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{RequiredNestedAssociate,String}', to_jsonb(@p)) @@ -82,7 +82,7 @@ public override async Task Update_property_on_projected_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{String}', to_jsonb(@p)) @@ -113,7 +113,7 @@ public override async Task Update_associate_to_parameter() AssertExecuteUpdateSql( """ -@complex_type_p='?' (DbType = Object) +@complex_type_p='{"Id":1000,"Int":80,"Ints":[1,2,3],"Name":"Updated associate name","String":"Updated nested string","NestedCollection":[],"OptionalNestedAssociate":null,"RequiredNestedAssociate":{"Id":1000,"Int":80,"Ints":[1,2,3],"Name":"Updated nested name","String":"Updated nested string"}}' (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate" = @complex_type_p @@ -126,7 +126,7 @@ public override async Task Update_nested_associate_to_parameter() AssertExecuteUpdateSql( """ -@complex_type_p='?' (DbType = Object) +@complex_type_p='{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated nested name","String":"Updated nested string"}' (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{RequiredNestedAssociate}', @complex_type_p) @@ -161,7 +161,7 @@ public override async Task Update_associate_to_inline() AssertExecuteUpdateSql( """ -@complex_type_p='?' (DbType = Object) +@complex_type_p='{"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"}}' (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate" = @complex_type_p @@ -240,7 +240,7 @@ public override async Task Update_collection_to_parameter() AssertExecuteUpdateSql( """ -@complex_type_p='?' (DbType = Object) +@complex_type_p='[{"Id":1000,"Int":80,"Ints":[1,2,4],"Name":"Updated associate name1","String":"Updated associate string1","NestedCollection":[],"OptionalNestedAssociate":null,"RequiredNestedAssociate":{"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 associate name2","String":"Updated associate string2","NestedCollection":[],"OptionalNestedAssociate":null,"RequiredNestedAssociate":{"Id":1001,"Int":81,"Ints":[1,2,4],"Name":"Updated nested name2","String":"Updated nested string2"}}]' (DbType = Object) UPDATE "RootEntity" AS r SET "AssociateCollection" = @complex_type_p @@ -253,7 +253,7 @@ public override async Task Update_nested_collection_to_parameter() AssertExecuteUpdateSql( """ -@complex_type_p='?' (DbType = Object) +@complex_type_p='[{"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"}]' (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{NestedCollection}', @complex_type_p) @@ -318,7 +318,7 @@ public override async Task Update_primitive_collection_to_parameter() AssertExecuteUpdateSql( """ -@ints='?' (DbType = Object) +@ints='[1,2,4]' (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{Ints}', @ints) @@ -342,7 +342,7 @@ public override async Task Update_inside_primitive_collection() AssertExecuteUpdateSql( """ -@p='?' (DbType = Int32) +@p='99' UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{Ints,1}', to_jsonb(@p)) @@ -360,11 +360,11 @@ public override async Task Update_multiple_properties_inside_same_associate() AssertExecuteUpdateSql( """ -@p='?' -@p0='?' (DbType = Int32) +@p='foo_updated' +@p1='20' UPDATE "RootEntity" AS r -SET "RequiredAssociate" = jsonb_set(jsonb_set(r."RequiredAssociate", '{String}', to_jsonb(@p)), '{Int}', to_jsonb(@p0)) +SET "RequiredAssociate" = jsonb_set(jsonb_set(r."RequiredAssociate", '{String}', to_jsonb(@p)), '{Int}', to_jsonb(@p1)) """); } @@ -374,7 +374,7 @@ public override async Task Update_multiple_properties_inside_associates_and_on_e AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "Name" = r."Name" || 'Modified', @@ -390,7 +390,7 @@ public override async Task Update_multiple_projected_associates_via_anonymous_ty AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate" = jsonb_set(r."RequiredAssociate", '{String}', r."OptionalAssociate" -> 'String'), diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs index 14204c04b..efb462189 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonCollectionNpgsqlTest.cs @@ -141,7 +141,7 @@ public override async Task Index_parameter() AssertSql( """ -@i='?' (DbType = Int32) +@i='0' SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r @@ -214,6 +214,18 @@ FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS ("NestedCollectio """); } + public override async Task Index_on_nested_collection() + { + await base.Index_on_nested_collection(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" +FROM "RootEntity" AS r +WHERE (CAST(r."RequiredAssociate" #>> '{NestedCollection,0,Int}' AS integer)) = 8 +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousNpgsqlTest.cs index cda65c84d..8f67b0179 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousNpgsqlTest.cs @@ -86,6 +86,14 @@ public override async Task Where_HasValue_on_nullable_value_type() #endregion Value types + // https://github.com/dotnet/efcore/issues/34627 + public override async Task FromSql_on_root() + { + await Assert.ThrowsAnyAsync(base.FromSql_on_root); + + AssertSql(); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs index 90ad538a0..711d46b59 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonStructuralEqualityNpgsqlTest.cs @@ -100,7 +100,7 @@ public override async Task Nested_associate_with_parameter() AssertSql( """ -@entity_equality_nested='?' (DbType = Object) +@entity_equality_nested='{"Id":1000,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredAssociate_RequiredNestedAssociate","String":"foo"}' (DbType = Object) SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r @@ -138,7 +138,7 @@ public override async Task Nested_collection_with_parameter() AssertSql( """ -@entity_equality_nestedCollection='?' (DbType = Object) +@entity_equality_nestedCollection='[{"Id":1002,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredAssociate_NestedCollection_1","String":"foo"},{"Id":1003,"Int":8,"Ints":[1,2,3],"Name":"Root1_RequiredAssociate_NestedCollection_2","String":"foo"}]' (DbType = Object) SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r @@ -181,11 +181,11 @@ public override async Task Contains_with_parameter() // 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) -@entity_equality_nested_Name='?' -@entity_equality_nested_String='?' +@entity_equality_nested_Id='1002' (Nullable = true) +@entity_equality_nested_Int='8' (Nullable = true) +@entity_equality_nested_Ints='[1,2,3]' (DbType = Object) +@entity_equality_nested_Name='Root1_RequiredAssociate_NestedCollection_1' +@entity_equality_nested_String='foo' SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r @@ -208,12 +208,12 @@ public override async Task Contains_with_operators_composed_on_the_collection() AssertSql( """ -@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='?' +@get_Item_Int='106' +@entity_equality_get_Item_Id='3003' (Nullable = true) +@entity_equality_get_Item_Int='108' (Nullable = true) +@entity_equality_get_Item_Ints='[8,9,109]' (DbType = Object) +@entity_equality_get_Item_Name='Root3_RequiredAssociate_NestedCollection_2' +@entity_equality_get_Item_String='foo104' SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r @@ -236,15 +236,15 @@ public override async Task Contains_with_nested_and_composed_operators() AssertSql( """ -@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) -@entity_equality_get_Item_OptionalNestedAssociate='?' (DbType = Object) -@entity_equality_get_Item_RequiredNestedAssociate='?' (DbType = Object) +@get_Item_Id='302' +@entity_equality_get_Item_Id='303' (Nullable = true) +@entity_equality_get_Item_Int='130' (Nullable = true) +@entity_equality_get_Item_Ints='[8,9,131]' (DbType = Object) +@entity_equality_get_Item_Name='Root3_AssociateCollection_2' +@entity_equality_get_Item_String='foo115' +@entity_equality_get_Item_NestedCollection='[{"Id":3014,"Int":136,"Ints":[8,9,137],"Name":"Root3_AssociateCollection_2_NestedCollection_1","String":"foo118"},{"Id":3015,"Int":138,"Ints":[8,9,139],"Name":"Root3_Root1_AssociateCollection_2_NestedCollection_2","String":"foo119"}]' (DbType = Object) +@entity_equality_get_Item_OptionalNestedAssociate='{"Id":3013,"Int":134,"Ints":[8,9,135],"Name":"Root3_AssociateCollection_2_OptionalNestedAssociate","String":"foo117"}' (DbType = Object) +@entity_equality_get_Item_RequiredNestedAssociate='{"Id":3012,"Int":132,"Ints":[8,9,133],"Name":"Root3_AssociateCollection_2_RequiredNestedAssociate","String":"foo116"}' (DbType = Object) SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" FROM "RootEntity" AS r diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs index e338cb80c..81a810410 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingBulkUpdateNpgsqlTest.cs @@ -13,7 +13,7 @@ public override async Task Delete_entity_with_associations() AssertSql( """ -@deletableEntity_Name='?' +@deletableEntity_Name='Root3_With_different_values' DELETE FROM "RootEntity" AS r WHERE r."Name" = @deletableEntity_Name @@ -44,7 +44,7 @@ public override async Task Update_property_inside_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate_String" = @p @@ -69,7 +69,7 @@ public override async Task Update_property_inside_nested_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate_RequiredNestedAssociate_String" = @p @@ -82,7 +82,7 @@ public override async Task Update_property_on_projected_associate() AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate_String" = @p @@ -113,16 +113,20 @@ public override async Task Update_associate_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='?' -@complex_type_p_RequiredNestedAssociate_Id='?' (DbType = Int32) -@complex_type_p_RequiredNestedAssociate_Int='?' (DbType = Int32) -@complex_type_p_RequiredNestedAssociate_Ints='?' (DbType = Object) -@complex_type_p_RequiredNestedAssociate_Name='?' -@complex_type_p_RequiredNestedAssociate_String='?' +@complex_type_p_Id='1000' (Nullable = true) +@complex_type_p_Int='80' (Nullable = true) +@complex_type_p_Ints={ '1' +'2' +'3' } (DbType = Object) +@complex_type_p_Name='Updated associate name' +@complex_type_p_String='Updated nested string' +@complex_type_p_RequiredNestedAssociate_Id='1000' (Nullable = true) +@complex_type_p_RequiredNestedAssociate_Int='80' (Nullable = true) +@complex_type_p_RequiredNestedAssociate_Ints={ '1' +'2' +'3' } (DbType = Object) +@complex_type_p_RequiredNestedAssociate_Name='Updated nested name' +@complex_type_p_RequiredNestedAssociate_String='Updated nested string' UPDATE "RootEntity" AS r SET "RequiredAssociate_Id" = @complex_type_p_Id, @@ -149,11 +153,13 @@ public override async Task Update_nested_associate_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='?' +@complex_type_p_Id='1000' (Nullable = true) +@complex_type_p_Int='80' (Nullable = true) +@complex_type_p_Ints={ '1' +'2' +'4' } (DbType = Object) +@complex_type_p_Name='Updated nested name' +@complex_type_p_String='Updated nested string' UPDATE "RootEntity" AS r SET "RequiredAssociate_RequiredNestedAssociate_Id" = @complex_type_p_Id, @@ -176,16 +182,16 @@ public override async Task Update_associate_to_another_associate() "OptionalAssociate_Ints" = r."RequiredAssociate_Ints", "OptionalAssociate_Name" = r."RequiredAssociate_Name", "OptionalAssociate_String" = r."RequiredAssociate_String", - "OptionalAssociate_OptionalNestedAssociate_Id" = r."OptionalAssociate_OptionalNestedAssociate_Id", - "OptionalAssociate_OptionalNestedAssociate_Int" = r."OptionalAssociate_OptionalNestedAssociate_Int", - "OptionalAssociate_OptionalNestedAssociate_Ints" = r."OptionalAssociate_OptionalNestedAssociate_Ints", - "OptionalAssociate_OptionalNestedAssociate_Name" = r."OptionalAssociate_OptionalNestedAssociate_Name", - "OptionalAssociate_OptionalNestedAssociate_String" = r."OptionalAssociate_OptionalNestedAssociate_String", - "OptionalAssociate_RequiredNestedAssociate_Id" = r."OptionalAssociate_RequiredNestedAssociate_Id", - "OptionalAssociate_RequiredNestedAssociate_Int" = r."OptionalAssociate_RequiredNestedAssociate_Int", - "OptionalAssociate_RequiredNestedAssociate_Ints" = r."OptionalAssociate_RequiredNestedAssociate_Ints", - "OptionalAssociate_RequiredNestedAssociate_Name" = r."OptionalAssociate_RequiredNestedAssociate_Name", - "OptionalAssociate_RequiredNestedAssociate_String" = r."OptionalAssociate_RequiredNestedAssociate_String" + "OptionalAssociate_OptionalNestedAssociate_Id" = r."RequiredAssociate_OptionalNestedAssociate_Id", + "OptionalAssociate_OptionalNestedAssociate_Int" = r."RequiredAssociate_OptionalNestedAssociate_Int", + "OptionalAssociate_OptionalNestedAssociate_Ints" = r."RequiredAssociate_OptionalNestedAssociate_Ints", + "OptionalAssociate_OptionalNestedAssociate_Name" = r."RequiredAssociate_OptionalNestedAssociate_Name", + "OptionalAssociate_OptionalNestedAssociate_String" = r."RequiredAssociate_OptionalNestedAssociate_String", + "OptionalAssociate_RequiredNestedAssociate_Id" = r."RequiredAssociate_RequiredNestedAssociate_Id", + "OptionalAssociate_RequiredNestedAssociate_Int" = r."RequiredAssociate_RequiredNestedAssociate_Int", + "OptionalAssociate_RequiredNestedAssociate_Ints" = r."RequiredAssociate_RequiredNestedAssociate_Ints", + "OptionalAssociate_RequiredNestedAssociate_Name" = r."RequiredAssociate_RequiredNestedAssociate_Name", + "OptionalAssociate_RequiredNestedAssociate_String" = r."RequiredAssociate_RequiredNestedAssociate_String" """); } @@ -210,16 +216,20 @@ public override async Task Update_associate_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='?' -@complex_type_p_RequiredNestedAssociate_Id='?' (DbType = Int32) -@complex_type_p_RequiredNestedAssociate_Int='?' (DbType = Int32) -@complex_type_p_RequiredNestedAssociate_Ints='?' (DbType = Object) -@complex_type_p_RequiredNestedAssociate_Name='?' -@complex_type_p_RequiredNestedAssociate_String='?' +@complex_type_p_Id='1000' (Nullable = true) +@complex_type_p_Int='70' (Nullable = true) +@complex_type_p_Ints={ '1' +'2' +'4' } (DbType = Object) +@complex_type_p_Name='Updated associate name' +@complex_type_p_String='Updated associate string' +@complex_type_p_RequiredNestedAssociate_Id='1000' (Nullable = true) +@complex_type_p_RequiredNestedAssociate_Int='80' (Nullable = true) +@complex_type_p_RequiredNestedAssociate_Ints={ '1' +'2' +'4' } (DbType = Object) +@complex_type_p_RequiredNestedAssociate_Name='Updated nested name' +@complex_type_p_RequiredNestedAssociate_String='Updated nested string' UPDATE "RootEntity" AS r SET "RequiredAssociate_Id" = @complex_type_p_Id, @@ -429,7 +439,9 @@ public override async Task Update_primitive_collection_to_parameter() AssertExecuteUpdateSql( """ -@ints='?' (DbType = Object) +@ints={ '1' +'2' +'4' } (DbType = Object) UPDATE "RootEntity" AS r SET "RequiredAssociate_Ints" = @ints @@ -465,12 +477,12 @@ public override async Task Update_multiple_properties_inside_same_associate() AssertExecuteUpdateSql( """ -@p='?' -@p0='?' (DbType = Int32) +@p='foo_updated' +@p1='20' UPDATE "RootEntity" AS r SET "RequiredAssociate_String" = @p, - "RequiredAssociate_Int" = @p0 + "RequiredAssociate_Int" = @p1 """); } @@ -480,7 +492,7 @@ public override async Task Update_multiple_properties_inside_associates_and_on_e AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "Name" = r."Name" || 'Modified', @@ -496,7 +508,7 @@ public override async Task Update_multiple_projected_associates_via_anonymous_ty AssertExecuteUpdateSql( """ -@p='?' +@p='foo_updated' UPDATE "RootEntity" AS r SET "RequiredAssociate_String" = r."OptionalAssociate_String", diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs index 7c32a1764..dfbc06f0a 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousNpgsqlTest.cs @@ -84,6 +84,17 @@ WHERE v."OptionalAssociate_Id" IS NOT NULL #endregion Value types + + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT * FROM "RootEntity" +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs index 6cb2d912c..3019ac063 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityNpgsqlTest.cs @@ -16,7 +16,7 @@ public override async Task Two_associates() """ SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String" FROM "RootEntity" AS r -WHERE r."RequiredAssociate_Id" = r."OptionalAssociate_Id" AND r."RequiredAssociate_Int" = r."OptionalAssociate_Int" AND r."RequiredAssociate_Ints" = r."OptionalAssociate_Ints" AND r."RequiredAssociate_Name" = r."OptionalAssociate_Name" AND r."RequiredAssociate_String" = r."OptionalAssociate_String" AND (r."RequiredAssociate_OptionalNestedAssociate_Id" = r."RequiredAssociate_OptionalNestedAssociate_Id" OR r."RequiredAssociate_OptionalNestedAssociate_Id" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Int" = r."RequiredAssociate_OptionalNestedAssociate_Int" OR r."RequiredAssociate_OptionalNestedAssociate_Int" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Ints" = r."RequiredAssociate_OptionalNestedAssociate_Ints" OR r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Name" = r."RequiredAssociate_OptionalNestedAssociate_Name" OR r."RequiredAssociate_OptionalNestedAssociate_Name" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_String" = r."RequiredAssociate_OptionalNestedAssociate_String" OR r."RequiredAssociate_OptionalNestedAssociate_String" IS NULL) AND r."RequiredAssociate_RequiredNestedAssociate_Id" = r."RequiredAssociate_RequiredNestedAssociate_Id" AND r."RequiredAssociate_RequiredNestedAssociate_Int" = r."RequiredAssociate_RequiredNestedAssociate_Int" AND r."RequiredAssociate_RequiredNestedAssociate_Ints" = r."RequiredAssociate_RequiredNestedAssociate_Ints" AND r."RequiredAssociate_RequiredNestedAssociate_Name" = r."RequiredAssociate_RequiredNestedAssociate_Name" AND r."RequiredAssociate_RequiredNestedAssociate_String" = r."RequiredAssociate_RequiredNestedAssociate_String" +WHERE r."RequiredAssociate_Id" = r."OptionalAssociate_Id" AND r."RequiredAssociate_Int" = r."OptionalAssociate_Int" AND r."RequiredAssociate_Ints" = r."OptionalAssociate_Ints" AND r."RequiredAssociate_Name" = r."OptionalAssociate_Name" AND r."RequiredAssociate_String" = r."OptionalAssociate_String" AND (r."RequiredAssociate_OptionalNestedAssociate_Id" = r."OptionalAssociate_OptionalNestedAssociate_Id" OR (r."RequiredAssociate_OptionalNestedAssociate_Id" IS NULL AND r."OptionalAssociate_OptionalNestedAssociate_Id" IS NULL)) AND (r."RequiredAssociate_OptionalNestedAssociate_Int" = r."OptionalAssociate_OptionalNestedAssociate_Int" OR (r."RequiredAssociate_OptionalNestedAssociate_Int" IS NULL AND r."OptionalAssociate_OptionalNestedAssociate_Int" IS NULL)) AND (r."RequiredAssociate_OptionalNestedAssociate_Ints" = r."OptionalAssociate_OptionalNestedAssociate_Ints" OR (r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NULL AND r."OptionalAssociate_OptionalNestedAssociate_Ints" IS NULL)) AND (r."RequiredAssociate_OptionalNestedAssociate_Name" = r."OptionalAssociate_OptionalNestedAssociate_Name" OR (r."RequiredAssociate_OptionalNestedAssociate_Name" IS NULL AND r."OptionalAssociate_OptionalNestedAssociate_Name" IS NULL)) AND (r."RequiredAssociate_OptionalNestedAssociate_String" = r."OptionalAssociate_OptionalNestedAssociate_String" OR (r."RequiredAssociate_OptionalNestedAssociate_String" IS NULL AND r."OptionalAssociate_OptionalNestedAssociate_String" IS NULL)) AND r."RequiredAssociate_RequiredNestedAssociate_Id" = r."OptionalAssociate_RequiredNestedAssociate_Id" AND r."RequiredAssociate_RequiredNestedAssociate_Int" = r."OptionalAssociate_RequiredNestedAssociate_Int" AND r."RequiredAssociate_RequiredNestedAssociate_Ints" = r."OptionalAssociate_RequiredNestedAssociate_Ints" AND r."RequiredAssociate_RequiredNestedAssociate_Name" = r."OptionalAssociate_RequiredNestedAssociate_Name" AND r."RequiredAssociate_RequiredNestedAssociate_String" = r."OptionalAssociate_RequiredNestedAssociate_String" """); } @@ -40,7 +40,7 @@ public override async Task Not_equals() """ SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String" FROM "RootEntity" AS r -WHERE r."RequiredAssociate_Id" <> r."OptionalAssociate_Id" OR r."OptionalAssociate_Id" IS NULL OR r."RequiredAssociate_Int" <> r."OptionalAssociate_Int" OR r."OptionalAssociate_Int" IS NULL OR r."RequiredAssociate_Ints" <> r."OptionalAssociate_Ints" OR r."OptionalAssociate_Ints" IS NULL OR r."RequiredAssociate_Name" <> r."OptionalAssociate_Name" OR r."OptionalAssociate_Name" IS NULL OR r."RequiredAssociate_String" <> r."OptionalAssociate_String" OR r."OptionalAssociate_String" IS NULL OR ((r."RequiredAssociate_OptionalNestedAssociate_Id" <> r."RequiredAssociate_OptionalNestedAssociate_Id" OR r."RequiredAssociate_OptionalNestedAssociate_Id" IS NULL) AND r."RequiredAssociate_OptionalNestedAssociate_Id" IS NOT NULL) OR ((r."RequiredAssociate_OptionalNestedAssociate_Int" <> r."RequiredAssociate_OptionalNestedAssociate_Int" OR r."RequiredAssociate_OptionalNestedAssociate_Int" IS NULL) AND r."RequiredAssociate_OptionalNestedAssociate_Int" IS NOT NULL) OR ((r."RequiredAssociate_OptionalNestedAssociate_Ints" <> r."RequiredAssociate_OptionalNestedAssociate_Ints" OR r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NULL) AND r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NOT NULL) OR ((r."RequiredAssociate_OptionalNestedAssociate_Name" <> r."RequiredAssociate_OptionalNestedAssociate_Name" OR r."RequiredAssociate_OptionalNestedAssociate_Name" IS NULL) AND r."RequiredAssociate_OptionalNestedAssociate_Name" IS NOT NULL) OR ((r."RequiredAssociate_OptionalNestedAssociate_String" <> r."RequiredAssociate_OptionalNestedAssociate_String" OR r."RequiredAssociate_OptionalNestedAssociate_String" IS NULL) AND r."RequiredAssociate_OptionalNestedAssociate_String" IS NOT NULL) OR r."RequiredAssociate_RequiredNestedAssociate_Id" <> r."RequiredAssociate_RequiredNestedAssociate_Id" OR r."RequiredAssociate_RequiredNestedAssociate_Id" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Int" <> r."RequiredAssociate_RequiredNestedAssociate_Int" OR r."RequiredAssociate_RequiredNestedAssociate_Int" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Ints" <> r."RequiredAssociate_RequiredNestedAssociate_Ints" OR r."RequiredAssociate_RequiredNestedAssociate_Ints" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Name" <> r."RequiredAssociate_RequiredNestedAssociate_Name" OR r."RequiredAssociate_RequiredNestedAssociate_Name" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_String" <> r."RequiredAssociate_RequiredNestedAssociate_String" OR r."RequiredAssociate_RequiredNestedAssociate_String" IS NULL +WHERE r."RequiredAssociate_Id" <> r."OptionalAssociate_Id" OR r."OptionalAssociate_Id" IS NULL OR r."RequiredAssociate_Int" <> r."OptionalAssociate_Int" OR r."OptionalAssociate_Int" IS NULL OR r."RequiredAssociate_Ints" <> r."OptionalAssociate_Ints" OR r."OptionalAssociate_Ints" IS NULL OR r."RequiredAssociate_Name" <> r."OptionalAssociate_Name" OR r."OptionalAssociate_Name" IS NULL OR r."RequiredAssociate_String" <> r."OptionalAssociate_String" OR r."OptionalAssociate_String" IS NULL OR ((r."RequiredAssociate_OptionalNestedAssociate_Id" <> r."OptionalAssociate_OptionalNestedAssociate_Id" OR r."RequiredAssociate_OptionalNestedAssociate_Id" IS NULL OR r."OptionalAssociate_OptionalNestedAssociate_Id" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Id" IS NOT NULL OR r."OptionalAssociate_OptionalNestedAssociate_Id" IS NOT NULL)) OR ((r."RequiredAssociate_OptionalNestedAssociate_Int" <> r."OptionalAssociate_OptionalNestedAssociate_Int" OR r."RequiredAssociate_OptionalNestedAssociate_Int" IS NULL OR r."OptionalAssociate_OptionalNestedAssociate_Int" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Int" IS NOT NULL OR r."OptionalAssociate_OptionalNestedAssociate_Int" IS NOT NULL)) OR ((r."RequiredAssociate_OptionalNestedAssociate_Ints" <> r."OptionalAssociate_OptionalNestedAssociate_Ints" OR r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NULL OR r."OptionalAssociate_OptionalNestedAssociate_Ints" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Ints" IS NOT NULL OR r."OptionalAssociate_OptionalNestedAssociate_Ints" IS NOT NULL)) OR ((r."RequiredAssociate_OptionalNestedAssociate_Name" <> r."OptionalAssociate_OptionalNestedAssociate_Name" OR r."RequiredAssociate_OptionalNestedAssociate_Name" IS NULL OR r."OptionalAssociate_OptionalNestedAssociate_Name" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_Name" IS NOT NULL OR r."OptionalAssociate_OptionalNestedAssociate_Name" IS NOT NULL)) OR ((r."RequiredAssociate_OptionalNestedAssociate_String" <> r."OptionalAssociate_OptionalNestedAssociate_String" OR r."RequiredAssociate_OptionalNestedAssociate_String" IS NULL OR r."OptionalAssociate_OptionalNestedAssociate_String" IS NULL) AND (r."RequiredAssociate_OptionalNestedAssociate_String" IS NOT NULL OR r."OptionalAssociate_OptionalNestedAssociate_String" IS NOT NULL)) OR r."RequiredAssociate_RequiredNestedAssociate_Id" <> r."OptionalAssociate_RequiredNestedAssociate_Id" OR r."OptionalAssociate_RequiredNestedAssociate_Id" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Int" <> r."OptionalAssociate_RequiredNestedAssociate_Int" OR r."OptionalAssociate_RequiredNestedAssociate_Int" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Ints" <> r."OptionalAssociate_RequiredNestedAssociate_Ints" OR r."OptionalAssociate_RequiredNestedAssociate_Ints" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_Name" <> r."OptionalAssociate_RequiredNestedAssociate_Name" OR r."OptionalAssociate_RequiredNestedAssociate_Name" IS NULL OR r."RequiredAssociate_RequiredNestedAssociate_String" <> r."OptionalAssociate_RequiredNestedAssociate_String" OR r."OptionalAssociate_RequiredNestedAssociate_String" IS NULL """); } @@ -98,11 +98,13 @@ public override async Task Nested_associate_with_parameter() AssertSql( """ -@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='?' +@entity_equality_nested_Id='1000' (Nullable = true) +@entity_equality_nested_Int='8' (Nullable = true) +@entity_equality_nested_Ints={ '1' +'2' +'3' } (DbType = Object) +@entity_equality_nested_Name='Root1_RequiredAssociate_RequiredNestedAssociate' +@entity_equality_nested_String='foo' SELECT r."Id", r."Name", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r."RequiredAssociate_Id", r."RequiredAssociate_Int", r."RequiredAssociate_Ints", r."RequiredAssociate_Name", r."RequiredAssociate_String", r."RequiredAssociate_OptionalNestedAssociate_Id", r."RequiredAssociate_OptionalNestedAssociate_Int", r."RequiredAssociate_OptionalNestedAssociate_Ints", r."RequiredAssociate_OptionalNestedAssociate_Name", r."RequiredAssociate_OptionalNestedAssociate_String", r."RequiredAssociate_RequiredNestedAssociate_Id", r."RequiredAssociate_RequiredNestedAssociate_Int", r."RequiredAssociate_RequiredNestedAssociate_Ints", r."RequiredAssociate_RequiredNestedAssociate_Name", r."RequiredAssociate_RequiredNestedAssociate_String" FROM "RootEntity" AS r diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs index 923a99ff1..ccb7be3f9 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsCollectionNpgsqlTest.cs @@ -263,6 +263,14 @@ SELECT max(n."Int") """); } + + public override async Task Index_on_nested_collection() + { + await base.Index_on_nested_collection(); + + AssertSql(); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs index e0de33289..914dcb0b3 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousNpgsqlTest.cs @@ -96,6 +96,36 @@ LEFT JOIN ( #endregion Simple filters + + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT m."Id", m."Name", m."OptionalAssociateId", m."RequiredAssociateId", a."Id", n."Id", n0."Id", a0."Id", n1."Id", n2."Id", s."Id", s."CollectionRootId", s."Int", s."Ints", s."Name", s."OptionalNestedAssociateId", s."RequiredNestedAssociateId", s."String", s."Id0", s."Id1", s."Id2", s."CollectionAssociateId", s."Int0", s."Ints0", s."Name0", s."String0", s."CollectionAssociateId0", s."Int1", s."Ints1", s."Name1", s."String1", s."CollectionAssociateId1", s."Int2", s."Ints2", s."Name2", s."String2", a."CollectionRootId", a."Int", a."Ints", a."Name", a."OptionalNestedAssociateId", a."RequiredNestedAssociateId", a."String", n6."Id", n6."CollectionAssociateId", n6."Int", n6."Ints", n6."Name", n6."String", n."CollectionAssociateId", n."Int", n."Ints", n."Name", n."String", n0."CollectionAssociateId", n0."Int", n0."Ints", n0."Name", n0."String", a0."CollectionRootId", a0."Int", a0."Ints", a0."Name", a0."OptionalNestedAssociateId", a0."RequiredNestedAssociateId", a0."String", n7."Id", n7."CollectionAssociateId", n7."Int", n7."Ints", n7."Name", n7."String", n1."CollectionAssociateId", n1."Int", n1."Ints", n1."Name", n1."String", n2."CollectionAssociateId", n2."Int", n2."Ints", n2."Name", n2."String" +FROM ( + SELECT * FROM "RootEntity" +) AS m +LEFT JOIN "AssociateType" AS a ON m."OptionalAssociateId" = a."Id" +LEFT JOIN "NestedAssociateType" AS n ON a."OptionalNestedAssociateId" = n."Id" +LEFT JOIN "NestedAssociateType" AS n0 ON a."RequiredNestedAssociateId" = n0."Id" +INNER JOIN "AssociateType" AS a0 ON m."RequiredAssociateId" = a0."Id" +LEFT JOIN "NestedAssociateType" AS n1 ON a0."OptionalNestedAssociateId" = n1."Id" +INNER JOIN "NestedAssociateType" AS n2 ON a0."RequiredNestedAssociateId" = n2."Id" +LEFT JOIN ( + SELECT a1."Id", a1."CollectionRootId", a1."Int", a1."Ints", a1."Name", a1."OptionalNestedAssociateId", a1."RequiredNestedAssociateId", a1."String", n3."Id" AS "Id0", n4."Id" AS "Id1", n5."Id" AS "Id2", n5."CollectionAssociateId", n5."Int" AS "Int0", n5."Ints" AS "Ints0", n5."Name" AS "Name0", n5."String" AS "String0", n3."CollectionAssociateId" AS "CollectionAssociateId0", n3."Int" AS "Int1", n3."Ints" AS "Ints1", n3."Name" AS "Name1", n3."String" AS "String1", n4."CollectionAssociateId" AS "CollectionAssociateId1", n4."Int" AS "Int2", n4."Ints" AS "Ints2", n4."Name" AS "Name2", n4."String" AS "String2" + FROM "AssociateType" AS a1 + LEFT JOIN "NestedAssociateType" AS n3 ON a1."OptionalNestedAssociateId" = n3."Id" + INNER JOIN "NestedAssociateType" AS n4 ON a1."RequiredNestedAssociateId" = n4."Id" + LEFT JOIN "NestedAssociateType" AS n5 ON a1."Id" = n5."CollectionAssociateId" +) AS s ON m."Id" = s."CollectionRootId" +LEFT JOIN "NestedAssociateType" AS n6 ON a."Id" = n6."CollectionAssociateId" +LEFT JOIN "NestedAssociateType" AS n7 ON a0."Id" = n7."CollectionAssociateId" +ORDER BY m."Id" NULLS FIRST, a."Id" NULLS FIRST, n."Id" NULLS FIRST, n0."Id" NULLS FIRST, a0."Id" NULLS FIRST, n1."Id" NULLS FIRST, n2."Id" NULLS FIRST, s."Id" NULLS FIRST, s."Id0" NULLS FIRST, s."Id1" NULLS FIRST, s."Id2" NULLS FIRST, n6."Id" NULLS FIRST +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs index e062849bf..f0ec97362 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonCollectionNpgsqlTest.cs @@ -249,6 +249,18 @@ FROM ROWS FROM (jsonb_to_recordset(r."AssociateCollection") AS ("NestedCollectio """); } + public override async Task Index_on_nested_collection() + { + await base.Index_on_nested_collection(); + + AssertSql( + """ +SELECT r."Id", r."Name", r."AssociateCollection", r."OptionalAssociate", r."RequiredAssociate" +FROM "RootEntity" AS r +WHERE (CAST(r."RequiredAssociate" #>> '{NestedCollection,0,Int}' AS integer)) = 8 +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousNpgsqlTest.cs index 72ba854d4..9d79312ff 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousNpgsqlTest.cs @@ -48,6 +48,19 @@ public override async Task Where_on_nested_associate_scalar_property() #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT m."Id", m."Name", m."AssociateCollection", m."OptionalAssociate", m."RequiredAssociate" +FROM ( + SELECT * FROM "RootEntity" +) AS m +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs index ceda85ec4..0d768c945 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsCollectionNpgsqlTest.cs @@ -266,6 +266,13 @@ SELECT max(r1."Int") """); } + public override async Task Index_on_nested_collection() + { + await base.Index_on_nested_collection(); + + AssertSql(); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs index fa3d39c68..ce1e54c35 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousNpgsqlTest.cs @@ -96,6 +96,36 @@ LEFT JOIN ( #endregion Simple filters + + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT m."Id", m."Name", o."RootEntityId", o0."AssociateTypeRootEntityId", o1."AssociateTypeRootEntityId", r."RootEntityId", r0."AssociateTypeRootEntityId", r1."AssociateTypeRootEntityId", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."AssociateTypeRootEntityId", s."AssociateTypeId", s."AssociateTypeRootEntityId0", s."AssociateTypeId0", s."AssociateTypeRootEntityId1", s."AssociateTypeId1", 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", o."Id", o."Int", o."Ints", o."Name", o."String", o2."AssociateTypeRootEntityId", 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", r."Id", r."Int", r."Ints", r."Name", r."String", r6."AssociateTypeRootEntityId", r6."Id", r6."Int", r6."Ints", r6."Name", r6."String", r0."Id", r0."Int", r0."Ints", r0."Name", r0."String", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String" +FROM ( + SELECT * FROM "RootEntity" +) AS m +LEFT JOIN "OptionalRelated" AS o ON m."Id" = o."RootEntityId" +LEFT JOIN "OptionalRelated_OptionalNested" AS o0 ON o."RootEntityId" = o0."AssociateTypeRootEntityId" +LEFT JOIN "OptionalRelated_RequiredNested" AS o1 ON o."RootEntityId" = o1."AssociateTypeRootEntityId" +LEFT JOIN "RequiredRelated" AS r ON m."Id" = r."RootEntityId" +LEFT JOIN "RequiredRelated_OptionalNested" AS r0 ON r."RootEntityId" = r0."AssociateTypeRootEntityId" +LEFT JOIN "RequiredRelated_RequiredNested" AS r1 ON r."RootEntityId" = r1."AssociateTypeRootEntityId" +LEFT JOIN ( + SELECT r2."RootEntityId", r2."Id", r2."Int", r2."Ints", r2."Name", r2."String", r3."AssociateTypeRootEntityId", r3."AssociateTypeId", r4."AssociateTypeRootEntityId" AS "AssociateTypeRootEntityId0", r4."AssociateTypeId" AS "AssociateTypeId0", r5."AssociateTypeRootEntityId" AS "AssociateTypeRootEntityId1", r5."AssociateTypeId" AS "AssociateTypeId1", r5."Id" AS "Id0", r5."Int" AS "Int0", r5."Ints" AS "Ints0", r5."Name" AS "Name0", r5."String" AS "String0", r3."Id" AS "Id1", r3."Int" AS "Int1", r3."Ints" AS "Ints1", r3."Name" AS "Name1", r3."String" AS "String1", r4."Id" AS "Id2", r4."Int" AS "Int2", r4."Ints" AS "Ints2", r4."Name" AS "Name2", r4."String" AS "String2" + FROM "RelatedCollection" AS r2 + LEFT JOIN "RelatedCollection_OptionalNested" AS r3 ON r2."RootEntityId" = r3."AssociateTypeRootEntityId" AND r2."Id" = r3."AssociateTypeId" + LEFT JOIN "RelatedCollection_RequiredNested" AS r4 ON r2."RootEntityId" = r4."AssociateTypeRootEntityId" AND r2."Id" = r4."AssociateTypeId" + LEFT JOIN "RelatedCollection_NestedCollection" AS r5 ON r2."RootEntityId" = r5."AssociateTypeRootEntityId" AND r2."Id" = r5."AssociateTypeId" +) AS s ON m."Id" = s."RootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o2 ON o."RootEntityId" = o2."AssociateTypeRootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r6 ON r."RootEntityId" = r6."AssociateTypeRootEntityId" +ORDER BY m."Id" NULLS FIRST, o."RootEntityId" NULLS FIRST, o0."AssociateTypeRootEntityId" NULLS FIRST, o1."AssociateTypeRootEntityId" NULLS FIRST, r."RootEntityId" NULLS FIRST, r0."AssociateTypeRootEntityId" NULLS FIRST, r1."AssociateTypeRootEntityId" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."AssociateTypeRootEntityId" NULLS FIRST, s."AssociateTypeId" NULLS FIRST, s."AssociateTypeRootEntityId0" NULLS FIRST, s."AssociateTypeId0" NULLS FIRST, s."AssociateTypeRootEntityId1" NULLS FIRST, s."AssociateTypeId1" NULLS FIRST, s."Id0" NULLS FIRST, o2."AssociateTypeRootEntityId" NULLS FIRST, o2."Id" NULLS FIRST, r6."AssociateTypeRootEntityId" NULLS FIRST +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs index 3efb87879..98f595309 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousNpgsqlTest.cs @@ -78,6 +78,31 @@ WHEN r."OptionalAssociate_Id" IS NOT NULL AND r."OptionalAssociate_Int" IS NOT N #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT m."Id", m."Name", r."Id", r0."Id", s."RootEntityId", s."Id", s."Int", s."Ints", s."Name", s."String", s."AssociateTypeRootEntityId", s."AssociateTypeId", s."Id0", s."Int0", s."Ints0", s."Name0", s."String0", s."OptionalNestedAssociate_Id", s."OptionalNestedAssociate_Int", s."OptionalNestedAssociate_Ints", s."OptionalNestedAssociate_Name", s."OptionalNestedAssociate_String", s."RequiredNestedAssociate_Id", s."RequiredNestedAssociate_Int", s."RequiredNestedAssociate_Ints", s."RequiredNestedAssociate_Name", s."RequiredNestedAssociate_String", r."OptionalAssociate_Id", r."OptionalAssociate_Int", r."OptionalAssociate_Ints", r."OptionalAssociate_Name", r."OptionalAssociate_String", o."AssociateTypeRootEntityId", o."Id", o."Int", o."Ints", o."Name", o."String", r."OptionalAssociate_OptionalNestedAssociate_Id", r."OptionalAssociate_OptionalNestedAssociate_Int", r."OptionalAssociate_OptionalNestedAssociate_Ints", r."OptionalAssociate_OptionalNestedAssociate_Name", r."OptionalAssociate_OptionalNestedAssociate_String", r."OptionalAssociate_RequiredNestedAssociate_Id", r."OptionalAssociate_RequiredNestedAssociate_Int", r."OptionalAssociate_RequiredNestedAssociate_Ints", r."OptionalAssociate_RequiredNestedAssociate_Name", r."OptionalAssociate_RequiredNestedAssociate_String", r0."RequiredAssociate_Id", r0."RequiredAssociate_Int", r0."RequiredAssociate_Ints", r0."RequiredAssociate_Name", r0."RequiredAssociate_String", r3."AssociateTypeRootEntityId", r3."Id", r3."Int", r3."Ints", r3."Name", r3."String", r0."RequiredAssociate_OptionalNestedAssociate_Id", r0."RequiredAssociate_OptionalNestedAssociate_Int", r0."RequiredAssociate_OptionalNestedAssociate_Ints", r0."RequiredAssociate_OptionalNestedAssociate_Name", r0."RequiredAssociate_OptionalNestedAssociate_String", r0."RequiredAssociate_RequiredNestedAssociate_Id", r0."RequiredAssociate_RequiredNestedAssociate_Int", r0."RequiredAssociate_RequiredNestedAssociate_Ints", r0."RequiredAssociate_RequiredNestedAssociate_Name", r0."RequiredAssociate_RequiredNestedAssociate_String" +FROM ( + SELECT * FROM "RootEntity" +) AS m +LEFT JOIN "RootEntity" AS r ON m."Id" = r."Id" +LEFT JOIN "RootEntity" AS r0 ON m."Id" = r0."Id" +LEFT JOIN ( + SELECT r1."RootEntityId", r1."Id", r1."Int", r1."Ints", r1."Name", r1."String", r2."AssociateTypeRootEntityId", r2."AssociateTypeId", r2."Id" AS "Id0", r2."Int" AS "Int0", r2."Ints" AS "Ints0", r2."Name" AS "Name0", r2."String" AS "String0", r1."OptionalNestedAssociate_Id", r1."OptionalNestedAssociate_Int", r1."OptionalNestedAssociate_Ints", r1."OptionalNestedAssociate_Name", r1."OptionalNestedAssociate_String", r1."RequiredNestedAssociate_Id", r1."RequiredNestedAssociate_Int", r1."RequiredNestedAssociate_Ints", r1."RequiredNestedAssociate_Name", r1."RequiredNestedAssociate_String" + FROM "RelatedCollection" AS r1 + LEFT JOIN "RelatedCollection_NestedCollection" AS r2 ON r1."RootEntityId" = r2."AssociateTypeRootEntityId" AND r1."Id" = r2."AssociateTypeId" +) AS s ON m."Id" = s."RootEntityId" +LEFT JOIN "OptionalRelated_NestedCollection" AS o ON CASE + WHEN r."OptionalAssociate_Id" IS NOT NULL AND r."OptionalAssociate_Int" IS NOT NULL AND r."OptionalAssociate_Ints" IS NOT NULL AND r."OptionalAssociate_Name" IS NOT NULL AND r."OptionalAssociate_String" IS NOT NULL THEN r."Id" +END = o."AssociateTypeRootEntityId" +LEFT JOIN "RequiredRelated_NestedCollection" AS r3 ON r0."Id" = r3."AssociateTypeRootEntityId" +ORDER BY m."Id" NULLS FIRST, r."Id" NULLS FIRST, r0."Id" NULLS FIRST, s."RootEntityId" NULLS FIRST, s."Id" NULLS FIRST, s."AssociateTypeRootEntityId" NULLS FIRST, s."AssociateTypeId" NULLS FIRST, s."Id0" NULLS FIRST, o."AssociateTypeRootEntityId" NULLS FIRST, o."Id" NULLS FIRST, r3."AssociateTypeRootEntityId" NULLS FIRST +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/ComplexTypeQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/ComplexTypeQueryNpgsqlTest.cs index 73559df0f..b4465ca72 100644 --- a/test/EFCore.PG.FunctionalTests/Query/ComplexTypeQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/ComplexTypeQueryNpgsqlTest.cs @@ -182,7 +182,7 @@ public override async Task Complex_type_equals_complex_type(bool async) """ SELECT c."Id", c."Name", c."BillingAddress_AddressLine1", c."BillingAddress_AddressLine2", c."BillingAddress_Tags", c."BillingAddress_ZipCode", c."BillingAddress_Country_Code", c."BillingAddress_Country_FullName", c."OptionalAddress_AddressLine1", c."OptionalAddress_AddressLine2", c."OptionalAddress_Tags", c."OptionalAddress_ZipCode", c."OptionalAddress_Country_Code", c."OptionalAddress_Country_FullName", c."ShippingAddress_AddressLine1", c."ShippingAddress_AddressLine2", c."ShippingAddress_Tags", c."ShippingAddress_ZipCode", c."ShippingAddress_Country_Code", c."ShippingAddress_Country_FullName" FROM "Customer" AS c -WHERE c."ShippingAddress_AddressLine1" = c."BillingAddress_AddressLine1" AND (c."ShippingAddress_AddressLine2" = c."BillingAddress_AddressLine2" OR (c."ShippingAddress_AddressLine2" IS NULL AND c."BillingAddress_AddressLine2" IS NULL)) AND c."ShippingAddress_Tags" = c."BillingAddress_Tags" AND c."ShippingAddress_ZipCode" = c."BillingAddress_ZipCode" +WHERE c."ShippingAddress_AddressLine1" = c."BillingAddress_AddressLine1" AND (c."ShippingAddress_AddressLine2" = c."BillingAddress_AddressLine2" OR (c."ShippingAddress_AddressLine2" IS NULL AND c."BillingAddress_AddressLine2" IS NULL)) AND c."ShippingAddress_Tags" = c."BillingAddress_Tags" AND c."ShippingAddress_ZipCode" = c."BillingAddress_ZipCode" AND c."ShippingAddress_Country_Code" = c."BillingAddress_Country_Code" AND c."ShippingAddress_Country_FullName" = c."BillingAddress_Country_FullName" """); } @@ -560,7 +560,7 @@ public override async Task Struct_complex_type_equals_struct_complex_type(bool a """ SELECT v."Id", v."Name", v."BillingAddress_AddressLine1", v."BillingAddress_AddressLine2", v."BillingAddress_ZipCode", v."BillingAddress_Country_Code", v."BillingAddress_Country_FullName", v."ShippingAddress_AddressLine1", v."ShippingAddress_AddressLine2", v."ShippingAddress_ZipCode", v."ShippingAddress_Country_Code", v."ShippingAddress_Country_FullName" FROM "ValuedCustomer" AS v -WHERE v."ShippingAddress_AddressLine1" = v."BillingAddress_AddressLine1" AND (v."ShippingAddress_AddressLine2" = v."BillingAddress_AddressLine2" OR (v."ShippingAddress_AddressLine2" IS NULL AND v."BillingAddress_AddressLine2" IS NULL)) AND v."ShippingAddress_ZipCode" = v."BillingAddress_ZipCode" +WHERE v."ShippingAddress_AddressLine1" = v."BillingAddress_AddressLine1" AND (v."ShippingAddress_AddressLine2" = v."BillingAddress_AddressLine2" OR (v."ShippingAddress_AddressLine2" IS NULL AND v."BillingAddress_AddressLine2" IS NULL)) AND v."ShippingAddress_ZipCode" = v."BillingAddress_ZipCode" AND v."ShippingAddress_Country_Code" = v."BillingAddress_Country_Code" AND v."ShippingAddress_Country_FullName" = v."BillingAddress_Country_FullName" """); } @@ -1114,7 +1114,7 @@ public override async Task Project_entity_with_complex_type_pushdown_and_then_le AssertSql( """ @p='20' -@p0='30' +@p1='30' SELECT c3."BillingAddress_ZipCode" AS "Zip1", c4."ShippingAddress_ZipCode" AS "Zip2" FROM ( @@ -1132,7 +1132,7 @@ LEFT JOIN ( SELECT c1."Id", c1."Name", c1."BillingAddress_AddressLine1", c1."BillingAddress_AddressLine2", c1."BillingAddress_Tags", c1."BillingAddress_ZipCode", c1."BillingAddress_Country_Code", c1."BillingAddress_Country_FullName", c1."OptionalAddress_AddressLine1", c1."OptionalAddress_AddressLine2", c1."OptionalAddress_Tags", c1."OptionalAddress_ZipCode", c1."OptionalAddress_Country_Code", c1."OptionalAddress_Country_FullName", c1."ShippingAddress_AddressLine1", c1."ShippingAddress_AddressLine2", c1."ShippingAddress_Tags", c1."ShippingAddress_ZipCode", c1."ShippingAddress_Country_Code", c1."ShippingAddress_Country_FullName" FROM "Customer" AS c1 ORDER BY c1."Id" DESC NULLS LAST - LIMIT @p0 + LIMIT @p1 ) AS c2 ) AS c4 ON c3."Id" = c4."Id" """); diff --git a/test/EFCore.PG.FunctionalTests/Query/EntitySplittingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/EntitySplittingQueryNpgsqlTest.cs index 381b0370e..210303d02 100644 --- a/test/EFCore.PG.FunctionalTests/Query/EntitySplittingQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/EntitySplittingQueryNpgsqlTest.cs @@ -3,6 +3,19 @@ namespace Microsoft.EntityFrameworkCore.Query; public class EntitySplittingQueryNpgsqlTest(NonSharedFixture fixture) : EntitySplittingQueryTestBase(fixture) { + + public override async Task Compare_split_entity_to_null(bool async) + { + await base.Compare_split_entity_to_null(async); + + AssertSql( + """ +SELECT e."Id", e."EntityThreeId", e."IntValue1", e."IntValue2", s."IntValue3", e."IntValue4", e."StringValue1", e."StringValue2", e."StringValue3", e."StringValue4" +FROM "EntityOne" AS e +INNER JOIN "SplitEntityOnePart" AS s ON e."Id" = s."Id" +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/FiltersInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/FiltersInheritanceQueryNpgsqlTest.cs index df7a25876..846e54219 100644 --- a/test/EFCore.PG.FunctionalTests/Query/FiltersInheritanceQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/FiltersInheritanceQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class FiltersInheritanceQueryNpgsqlTest : FiltersInheritanceQueryTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlFixture.cs similarity index 71% rename from test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlFixture.cs index 8efe70c7d..b90ebf5ce 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlFixture.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCFiltersInheritanceQueryNpgsqlFixture : TPCInheritanceQueryNpgsqlFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlTest.cs similarity index 76% rename from test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlTest.cs index 26a0f386a..2bb3bf719 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCFiltersInheritanceQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCFiltersInheritanceQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCFiltersInheritanceQueryNpgsqlTest(TPCFiltersInheritanceQueryNpgsqlFixture fixture) : TPCFiltersInheritanceQueryTestBase(fixture); diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlFixture.cs similarity index 98% rename from test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlFixture.cs index 075c16d7e..beac44c49 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlFixture.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCGearsOfWarQueryNpgsqlFixture : TPCGearsOfWarQueryRelationalFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlTest.cs similarity index 98% rename from test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlTest.cs index 0ada4522f..be6b0adab 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCGearsOfWarQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCGearsOfWarQueryNpgsqlTest.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCGearsOfWarQueryNpgsqlTest : TPCGearsOfWarQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlFixture.cs new file mode 100644 index 000000000..236264c86 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlFixture.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPCInheritanceJsonQueryNpgsqlFixture : TPCInheritanceJsonQueryRelationalFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory + => NpgsqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlTest.cs new file mode 100644 index 000000000..af59db387 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceJsonQueryNpgsqlTest.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPCInheritanceJsonQueryNpgsqlTest(TPCInheritanceJsonQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPCInheritanceJsonQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT c."Id", c."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ComplexTypeCollection", c."ParentComplexType", c."ChildComplexType" +FROM "Coke" AS c +WHERE (CAST(c."ChildComplexType" ->> 'Int' AS integer)) = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType", u."ChildComplexType", u."ChildComplexType1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::jsonb AS "ChildComplexType1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."ParentComplexType", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType" AS "ChildComplexType1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE (CAST(u."ParentComplexType" ->> 'Int' AS integer)) = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT c."Id", c."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ComplexTypeCollection", c."ParentComplexType", c."ChildComplexType" +FROM "Coke" AS c +WHERE (CAST(c."ChildComplexType" #>> '{Nested,NestedInt}' AS integer)) = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType", u."ChildComplexType", u."ChildComplexType1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::jsonb AS "ChildComplexType1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."ParentComplexType", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType" AS "ChildComplexType1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE (CAST(u."ParentComplexType" #>> '{Nested,NestedInt}' AS integer)) = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType" +FROM "Coke" AS c +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT u."ParentComplexType" +FROM ( + SELECT d."ParentComplexType" + FROM "Drinks" AS d + UNION ALL + SELECT c."ParentComplexType" + FROM "Coke" AS c + UNION ALL + SELECT l."ParentComplexType" + FROM "Lilt" AS l + UNION ALL + SELECT t."ParentComplexType" + FROM "Tea" AS t +) AS u +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType" -> 'Nested' +FROM "Coke" AS c +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT u."ParentComplexType" -> 'Nested' +FROM ( + SELECT d."ParentComplexType" + FROM "Drinks" AS d + UNION ALL + SELECT c."ParentComplexType" + FROM "Coke" AS c + UNION ALL + SELECT l."ParentComplexType" + FROM "Lilt" AS l + UNION ALL + SELECT t."ParentComplexType" + FROM "Tea" AS t +) AS u +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType", u."ChildComplexType", u."ChildComplexType1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::jsonb AS "ChildComplexType1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."ParentComplexType", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."ParentComplexType", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType" AS "ChildComplexType1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(u."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c0 + WHERE c0."Int" > 59) = 2 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlFixture.cs similarity index 75% rename from test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlFixture.cs index 32c62cd2d..4b4f763ac 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlFixture.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCInheritanceQueryNpgsqlFixture : TPCInheritanceQueryFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlTest.cs new file mode 100644 index 000000000..427cd8c2a --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceQueryNpgsqlTest.cs @@ -0,0 +1,768 @@ +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPCInheritanceQueryNpgsqlTest(TPCInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPCInheritanceQueryTestBase(fixture, testOutputHelper) +{ + public override async Task Byte_enum_value_constant_used_in_projection(bool async) + { + await base.Byte_enum_value_constant_used_in_projection(async); + + AssertSql( + """ +SELECT CASE + WHEN k."IsFlightless" THEN 0 + ELSE 1 +END +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_filter_all_animals(bool async) + { + await base.Can_filter_all_animals(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."Name" = 'Great spotted kiwi' +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_include_animals(bool async) + { + await base.Can_include_animals(async); + + AssertSql( + """ +SELECT c."Id", c."Name", u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM "Countries" AS c +LEFT JOIN ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u ON c."Id" = u."CountryId" +ORDER BY c."Name" NULLS FIRST, c."Id" NULLS FIRST +"""); + } + + public override async Task Can_include_prey(bool async) + { + await base.Can_include_prey(async); + + AssertSql( + """ +SELECT e1."Id", e1."CountryId", e1."Name", e1."Species", e1."EagleId", e1."IsFlightless", e1."Group", u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group" + FROM "Eagle" AS e + LIMIT 2 +) AS e1 +LEFT JOIN ( + SELECT e0."Id", e0."CountryId", e0."Name", e0."Species", e0."EagleId", e0."IsFlightless", e0."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e0 + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u ON e1."Id" = u."EagleId" +ORDER BY e1."Id" NULLS FIRST +"""); + } + + // Seed data for the fixture manually inserts entities with IDs 1, 2; then this test attempts to insert another one with an auto-generated ID, + // but the PG sequence wasn't updated so produces 1, resulting in a conflict. The test should be consistent in either using either + // auto-generated IDs or not across the board. + public override Task Can_insert_update_delete() + => Assert.ThrowsAsync(base.Can_insert_update_delete); + + public override async Task Can_query_all_animals(bool async) + { + await base.Can_query_all_animals(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_birds(bool async) + { + await base.Can_query_all_birds(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_plants(bool async) + { + await base.Can_query_all_plants(async); + + AssertSql( + """ +SELECT u."Species", u."CountryId", u."Genus", u."Name", u."HasThorns", u."Discriminator" +FROM ( + SELECT d."Species", d."CountryId", d."Genus", d."Name", NULL AS "HasThorns", 'Daisy' AS "Discriminator" + FROM "Daisies" AS d + UNION ALL + SELECT r."Species", r."CountryId", r."Genus", r."Name", r."HasThorns", 'Rose' AS "Discriminator" + FROM "Roses" AS r +) AS u +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_types_when_shared_column(bool async) + { + await base.Can_query_all_types_when_shared_column(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType_Int", u."ParentComplexType_UniqueInt", u."ParentComplexType_Nested_NestedInt", u."ParentComplexType_Nested_UniqueInt", u."ChildComplexType_Int", u."ChildComplexType_UniqueInt", u."ChildComplexType_Nested_NestedInt", u."ChildComplexType_Nested_UniqueInt", u."ChildComplexType_Int1", u."ChildComplexType_UniqueInt1", u."ChildComplexType_Nested_NestedInt1", u."ChildComplexType_Nested_UniqueInt1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::int AS "ChildComplexType_Int1", NULL::int AS "ChildComplexType_UniqueInt1", NULL::int AS "ChildComplexType_Nested_NestedInt1", NULL::int AS "ChildComplexType_Nested_UniqueInt1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType_Int" AS "ChildComplexType_Int1", t."ChildComplexType_UniqueInt" AS "ChildComplexType_UniqueInt1", t."ChildComplexType_Nested_NestedInt" AS "ChildComplexType_Nested_NestedInt1", t."ChildComplexType_Nested_UniqueInt" AS "ChildComplexType_Nested_UniqueInt1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +"""); + } + + public override async Task Can_query_just_kiwis(bool async) + { + await base.Can_query_just_kiwis(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn" +FROM "Kiwi" AS k +LIMIT 2 +"""); + } + + public override async Task Can_query_just_roses(bool async) + { + await base.Can_query_just_roses(async); + + AssertSql( + """ +SELECT r."Species", r."CountryId", r."Genus", r."Name", r."HasThorns" +FROM "Roses" AS r +LIMIT 2 +"""); + } + + public override async Task Can_query_when_shared_column(bool async) + { + await base.Can_query_when_shared_column(async); + + AssertSql( + """ +SELECT c."Id", c."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ComplexTypeCollection", c."Int", c."UniqueInt", c."NestedInt", c."NestedComplexType_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Coke" AS c +LIMIT 2 +""", + // + """ +SELECT l."Id", l."SortIndex", l."LiltCO2", l."SugarGrams", l."ComplexTypeCollection", l."Int", l."UniqueInt", l."NestedInt", l."NestedComplexType_UniqueInt" +FROM "Lilt" AS l +LIMIT 2 +""", + // + """ +SELECT t."Id", t."SortIndex", t."CaffeineGrams", t."HasMilk", t."ComplexTypeCollection", t."Int", t."UniqueInt", t."NestedInt", t."NestedComplexType_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt" +FROM "Tea" AS t +LIMIT 2 +"""); + } + + public override async Task Can_use_backwards_is_animal(bool async) + { + await base.Can_use_backwards_is_animal(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_use_backwards_of_type_animal(bool async) + { + await base.Can_use_backwards_of_type_animal(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_use_is_kiwi(bool async) + { + await base.Can_use_is_kiwi(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_use_is_kiwi_with_cast(bool async) + { + await base.Can_use_is_kiwi_with_cast(async); + + AssertSql( + """ +SELECT CASE + WHEN u."Discriminator" = 'Kiwi' THEN u."FoundOn" + ELSE 0 +END AS "Value" +FROM ( + SELECT NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +"""); + } + + public override async Task Can_use_is_kiwi_in_projection(bool async) + { + await base.Can_use_is_kiwi_in_projection(async); + + AssertSql( + """ +SELECT u."Discriminator" = 'Kiwi' +FROM ( + SELECT 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +"""); + } + + public override async Task Can_use_is_kiwi_with_other_predicate(bool async) + { + await base.Can_use_is_kiwi_with_other_predicate(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."Discriminator" = 'Kiwi' AND u."CountryId" = 1 +"""); + } + + public override async Task Can_use_of_type_animal(bool async) + { + await base.Can_use_of_type_animal(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird(bool async) + { + await base.Can_use_of_type_bird(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_first(bool async) + { + await base.Can_use_of_type_bird_first(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +ORDER BY u."Species" NULLS FIRST +LIMIT 1 +"""); + } + + public override async Task Can_use_of_type_bird_predicate(bool async) + { + await base.Can_use_of_type_bird_predicate(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."CountryId" = 1 +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_with_projection(bool async) + { + await base.Can_use_of_type_bird_with_projection(async); + + AssertSql( + """ +SELECT e."EagleId" +FROM "Eagle" AS e +UNION ALL +SELECT k."EagleId" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_use_of_type_kiwi(bool async) + { + await base.Can_use_of_type_kiwi(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn", 'Kiwi' AS "Discriminator" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_use_of_type_kiwi_where_north_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_north_on_derived_property(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."FoundOn", u."Discriminator" +FROM ( + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."FoundOn" = 0 +"""); + } + + public override async Task Can_use_of_type_kiwi_where_south_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_south_on_derived_property(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."FoundOn", u."Discriminator" +FROM ( + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."FoundOn" = 1 +"""); + } + + public override async Task Can_use_of_type_rose(bool async) + { + await base.Can_use_of_type_rose(async); + + AssertSql( + """ +SELECT r."Species", r."CountryId", r."Genus", r."Name", r."HasThorns", 'Rose' AS "Discriminator" +FROM "Roses" AS r +"""); + } + + public override async Task Member_access_on_intermediate_type_works() + { + await base.Member_access_on_intermediate_type_works(); + + AssertSql( + """ +SELECT k."Name" +FROM "Kiwi" AS k +ORDER BY k."Name" NULLS FIRST +"""); + } + + public override async Task OfType_Union_OfType(bool async) + { + await base.OfType_Union_OfType(async); + + AssertSql(); + } + + public override async Task OfType_Union_subquery(bool async) + { + await base.OfType_Union_subquery(async); + + AssertSql(); + } + + public override Task Setting_foreign_key_to_a_different_type_throws() + => base.Setting_foreign_key_to_a_different_type_throws(); + + public override async Task Subquery_OfType(bool async) + { + await base.Subquery_OfType(async); + + AssertSql( + """ +@p='5' + +SELECT DISTINCT u0."Id", u0."CountryId", u0."Name", u0."Species", u0."EagleId", u0."IsFlightless", u0."FoundOn", u0."Discriminator" +FROM ( + SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."FoundOn", u."Discriminator" + FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k + ) AS u + ORDER BY u."Species" NULLS FIRST + LIMIT @p +) AS u0 +WHERE u0."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Union_entity_equality(bool async) + { + await base.Union_entity_equality(async); + + AssertSql(); + } + + public override async Task Union_siblings_with_duplicate_property_in_subquery(bool async) + { + await base.Union_siblings_with_duplicate_property_in_subquery(async); + + AssertSql(); + } + + public override async Task Is_operator_on_result_of_FirstOrDefault(bool async) + { + await base.Is_operator_on_result_of_FirstOrDefault(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT u0."Discriminator" + FROM ( + SELECT e0."Name", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e0 + UNION ALL + SELECT k0."Name", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k0 + ) AS u0 + WHERE u0."Name" = 'Great spotted kiwi' + LIMIT 1 + ) AS u1 + WHERE u1."Discriminator" = 'Kiwi') +ORDER BY u."Species" NULLS FIRST +"""); + } + + public override async Task Selecting_only_base_properties_on_base_type(bool async) + { + await base.Selecting_only_base_properties_on_base_type(async); + + AssertSql( + """ +SELECT e."Name" +FROM "Eagle" AS e +UNION ALL +SELECT k."Name" +FROM "Kiwi" AS k +"""); + } + + public override async Task Selecting_only_base_properties_on_derived_type(bool async) + { + await base.Selecting_only_base_properties_on_derived_type(async); + + AssertSql( + """ +SELECT e."Name" +FROM "Eagle" AS e +UNION ALL +SELECT k."Name" +FROM "Kiwi" AS k +"""); + } + + public override async Task Can_query_all_animal_views(bool async) + { + await base.Can_query_all_animal_views(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_derived_type(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_derived_type2(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type2(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_of_type(bool async) + { + await base.Discriminator_used_when_projection_over_of_type(async); + + AssertSql(); + } + + public override async Task Discriminator_with_cast_in_shadow_property(bool async) + { + await base.Discriminator_with_cast_in_shadow_property(async); + + AssertSql(); + } + + public override void Using_from_sql_throws() + { + base.Using_from_sql_throws(); + + AssertSql(); + } + + public override async Task Using_is_operator_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."Discriminator" = 'Eagle' +"""); + } + + public override async Task Using_is_operator_with_of_type_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_with_of_type_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."Discriminator" +FROM ( + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."Discriminator" = 'Eagle' +"""); + } + + public override async Task Using_OfType_on_multiple_type_with_no_result(bool async) + { + await base.Using_OfType_on_multiple_type_with_no_result(async); + + AssertSql(); + } + + public override async Task GetType_in_hierarchy_in_abstract_base_type(bool async) + { + await base.GetType_in_hierarchy_in_abstract_base_type(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling(async); + + AssertSql( + """ +SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" +FROM "Eagle" AS e +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" +FROM "Kiwi" AS k +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(async); + + AssertSql( + """ +SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" +FROM "Kiwi" AS k +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(async); + + AssertSql( + """ +SELECT u."Id", u."CountryId", u."Name", u."Species", u."EagleId", u."IsFlightless", u."Group", u."FoundOn", u."Discriminator" +FROM ( + SELECT e."Id", e."CountryId", e."Name", e."Species", e."EagleId", e."IsFlightless", e."Group", NULL AS "FoundOn", 'Eagle' AS "Discriminator" + FROM "Eagle" AS e + UNION ALL + SELECT k."Id", k."CountryId", k."Name", k."Species", k."EagleId", k."IsFlightless", NULL AS "Group", k."FoundOn", 'Kiwi' AS "Discriminator" + FROM "Kiwi" AS k +) AS u +WHERE u."Discriminator" <> 'Kiwi' +"""); + } + + public override async Task Primitive_collection_on_subtype(bool async) + { + await base.Primitive_collection_on_subtype(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType_Int", u."ParentComplexType_UniqueInt", u."ParentComplexType_Nested_NestedInt", u."ParentComplexType_Nested_UniqueInt", u."ChildComplexType_Int", u."ChildComplexType_UniqueInt", u."ChildComplexType_Nested_NestedInt", u."ChildComplexType_Nested_UniqueInt", u."ChildComplexType_Int1", u."ChildComplexType_UniqueInt1", u."ChildComplexType_Nested_NestedInt1", u."ChildComplexType_Nested_UniqueInt1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::int AS "ChildComplexType_Int1", NULL::int AS "ChildComplexType_UniqueInt1", NULL::int AS "ChildComplexType_Nested_NestedInt1", NULL::int AS "ChildComplexType_Nested_UniqueInt1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType_Int" AS "ChildComplexType_Int1", t."ChildComplexType_UniqueInt" AS "ChildComplexType_UniqueInt1", t."ChildComplexType_Nested_NestedInt" AS "ChildComplexType_Nested_NestedInt1", t."ChildComplexType_Nested_UniqueInt" AS "ChildComplexType_Nested_UniqueInt1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE cardinality(u."Ints") > 0 +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceTableSplittingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceTableSplittingQueryNpgsqlTest.cs new file mode 100644 index 000000000..2f2654dd9 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCInheritanceTableSplittingQueryNpgsqlTest.cs @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPCInheritanceTableSplittingQueryNpgsqlTest(TPCInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPCInheritanceTableSplittingQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT c."Id", c."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ComplexTypeCollection", c."Int", c."UniqueInt", c."NestedInt", c."NestedComplexType_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Coke" AS c +WHERE c."ChildComplexType_Int" = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType_Int", u."ParentComplexType_UniqueInt", u."ParentComplexType_Nested_NestedInt", u."ParentComplexType_Nested_UniqueInt", u."ChildComplexType_Int", u."ChildComplexType_UniqueInt", u."ChildComplexType_Nested_NestedInt", u."ChildComplexType_Nested_UniqueInt", u."ChildComplexType_Int1", u."ChildComplexType_UniqueInt1", u."ChildComplexType_Nested_NestedInt1", u."ChildComplexType_Nested_UniqueInt1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::int AS "ChildComplexType_Int1", NULL::int AS "ChildComplexType_UniqueInt1", NULL::int AS "ChildComplexType_Nested_NestedInt1", NULL::int AS "ChildComplexType_Nested_UniqueInt1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType_Int" AS "ChildComplexType_Int1", t."ChildComplexType_UniqueInt" AS "ChildComplexType_UniqueInt1", t."ChildComplexType_Nested_NestedInt" AS "ChildComplexType_Nested_NestedInt1", t."ChildComplexType_Nested_UniqueInt" AS "ChildComplexType_Nested_UniqueInt1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE u."ParentComplexType_Int" = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT c."Id", c."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ComplexTypeCollection", c."Int", c."UniqueInt", c."NestedInt", c."NestedComplexType_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Coke" AS c +WHERE c."ChildComplexType_Nested_NestedInt" = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType_Int", u."ParentComplexType_UniqueInt", u."ParentComplexType_Nested_NestedInt", u."ParentComplexType_Nested_UniqueInt", u."ChildComplexType_Int", u."ChildComplexType_UniqueInt", u."ChildComplexType_Nested_NestedInt", u."ChildComplexType_Nested_UniqueInt", u."ChildComplexType_Int1", u."ChildComplexType_UniqueInt1", u."ChildComplexType_Nested_NestedInt1", u."ChildComplexType_Nested_UniqueInt1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::int AS "ChildComplexType_Int1", NULL::int AS "ChildComplexType_UniqueInt1", NULL::int AS "ChildComplexType_Nested_NestedInt1", NULL::int AS "ChildComplexType_Nested_UniqueInt1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType_Int" AS "ChildComplexType_Int1", t."ChildComplexType_UniqueInt" AS "ChildComplexType_UniqueInt1", t."ChildComplexType_Nested_NestedInt" AS "ChildComplexType_Nested_NestedInt1", t."ChildComplexType_Nested_UniqueInt" AS "ChildComplexType_Nested_UniqueInt1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE u."ParentComplexType_Nested_NestedInt" = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Coke" AS c +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +UNION ALL +SELECT c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Coke" AS c +UNION ALL +SELECT l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Lilt" AS l +UNION ALL +SELECT t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Tea" AS t +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Coke" AS c +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +UNION ALL +SELECT c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Coke" AS c +UNION ALL +SELECT l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Lilt" AS l +UNION ALL +SELECT t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt" +FROM "Tea" AS t +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT u."Id", u."SortIndex", u."CaffeineGrams", u."CokeCO2", u."Ints", u."SugarGrams", u."LiltCO2", u."SugarGrams1", u."CaffeineGrams1", u."HasMilk", u."ComplexTypeCollection", u."ParentComplexType_Int", u."ParentComplexType_UniqueInt", u."ParentComplexType_Nested_NestedInt", u."ParentComplexType_Nested_UniqueInt", u."ChildComplexType_Int", u."ChildComplexType_UniqueInt", u."ChildComplexType_Nested_NestedInt", u."ChildComplexType_Nested_UniqueInt", u."ChildComplexType_Int1", u."ChildComplexType_UniqueInt1", u."ChildComplexType_Nested_NestedInt1", u."ChildComplexType_Nested_UniqueInt1", u."Discriminator" +FROM ( + SELECT d."Id", d."SortIndex", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL::int AS "LiltCO2", NULL::int AS "SugarGrams1", NULL::int AS "CaffeineGrams1", NULL::boolean AS "HasMilk", NULL::int AS "ChildComplexType_Int1", NULL::int AS "ChildComplexType_UniqueInt1", NULL::int AS "ChildComplexType_Nested_NestedInt1", NULL::int AS "ChildComplexType_Nested_UniqueInt1", 'Drink' AS "Discriminator" + FROM "Drinks" AS d + UNION ALL + SELECT c."Id", c."SortIndex", c."ComplexTypeCollection", c."Int" AS "ParentComplexType_Int", c."UniqueInt" AS "ParentComplexType_UniqueInt", c."NestedInt" AS "ParentComplexType_Nested_NestedInt", c."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Coke' AS "Discriminator" + FROM "Coke" AS c + UNION ALL + SELECT l."Id", l."SortIndex", l."ComplexTypeCollection", l."Int" AS "ParentComplexType_Int", l."UniqueInt" AS "ParentComplexType_UniqueInt", l."NestedInt" AS "ParentComplexType_Nested_NestedInt", l."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", l."LiltCO2", l."SugarGrams" AS "SugarGrams1", NULL AS "CaffeineGrams1", NULL AS "HasMilk", NULL AS "ChildComplexType_Int1", NULL AS "ChildComplexType_UniqueInt1", NULL AS "ChildComplexType_Nested_NestedInt1", NULL AS "ChildComplexType_Nested_UniqueInt1", 'Lilt' AS "Discriminator" + FROM "Lilt" AS l + UNION ALL + SELECT t."Id", t."SortIndex", t."ComplexTypeCollection", t."Int" AS "ParentComplexType_Int", t."UniqueInt" AS "ParentComplexType_UniqueInt", t."NestedInt" AS "ParentComplexType_Nested_NestedInt", t."NestedComplexType_UniqueInt" AS "ParentComplexType_Nested_UniqueInt", NULL AS "CaffeineGrams", NULL AS "CokeCO2", NULL AS "Ints", NULL AS "SugarGrams", NULL AS "ChildComplexType_Int", NULL AS "ChildComplexType_UniqueInt", NULL AS "ChildComplexType_Nested_NestedInt", NULL AS "ChildComplexType_Nested_UniqueInt", NULL AS "LiltCO2", NULL AS "SugarGrams1", t."CaffeineGrams" AS "CaffeineGrams1", t."HasMilk", t."ChildComplexType_Int" AS "ChildComplexType_Int1", t."ChildComplexType_UniqueInt" AS "ChildComplexType_UniqueInt1", t."ChildComplexType_Nested_NestedInt" AS "ChildComplexType_Nested_NestedInt1", t."ChildComplexType_Nested_UniqueInt" AS "ChildComplexType_Nested_UniqueInt1", 'Tea' AS "Discriminator" + FROM "Tea" AS t +) AS u +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(u."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c0 + WHERE c0."Int" > 59) = 2 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyNoTrackingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyNoTrackingQueryNpgsqlTest.cs similarity index 87% rename from test/EFCore.PG.FunctionalTests/Query/TPCManyToManyNoTrackingQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyNoTrackingQueryNpgsqlTest.cs index f9b4ae230..1471bd00e 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyNoTrackingQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyNoTrackingQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCManyToManyNoTrackingQueryNpgsqlTest : TPCManyToManyNoTrackingQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlFixture.cs similarity index 95% rename from test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlFixture.cs index cdccbb8a4..bfbe93b85 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlFixture.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCManyToManyQueryNpgsqlFixture : TPCManyToManyQueryRelationalFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlTest.cs similarity index 86% rename from test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlTest.cs index e275cee9f..c1e10ea93 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCManyToManyQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCManyToManyQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCManyToManyQueryNpgsqlTest : TPCManyToManyQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCRelationshipsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCRelationshipsQueryNpgsqlTest.cs similarity index 90% rename from test/EFCore.PG.FunctionalTests/Query/TPCRelationshipsQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCRelationshipsQueryNpgsqlTest.cs index c39506cb7..7cb72dff3 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPCRelationshipsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPCRelationshipsQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPCRelationshipsQueryNpgsqlTest : TPCRelationshipsQueryTestBase diff --git a/test/EFCore.PG.FunctionalTests/Query/TPHFiltersInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHFiltersInheritanceQueryNpgsqlFixture.cs similarity index 70% rename from test/EFCore.PG.FunctionalTests/Query/TPHFiltersInheritanceQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHFiltersInheritanceQueryNpgsqlFixture.cs index 63e19c296..9783cdbca 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPHFiltersInheritanceQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHFiltersInheritanceQueryNpgsqlFixture.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPHFiltersInheritanceQueryNpgsqlFixture : TPHInheritanceQueryNpgsqlFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlFixture.cs new file mode 100644 index 000000000..345627f66 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlFixture.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPHInheritanceJsonQueryNpgsqlFixture : TPHInheritanceJsonQueryRelationalFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory + => NpgsqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlTest.cs new file mode 100644 index 000000000..d1f0435a3 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceJsonQueryNpgsqlTest.cs @@ -0,0 +1,120 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPHInheritanceJsonQueryNpgsqlTest(TPHInheritanceJsonQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPHInheritanceJsonQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType", d."ChildComplexType" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 AND (CAST(d."ChildComplexType" ->> 'Int' AS integer)) = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", d."ChildComplexType", d."ChildComplexType" +FROM "Drinks" AS d +WHERE (CAST(d."ParentComplexType" ->> 'Int' AS integer)) = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType", d."ChildComplexType" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 AND (CAST(d."ChildComplexType" #>> '{Nested,NestedInt}' AS integer)) = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", d."ChildComplexType", d."ChildComplexType" +FROM "Drinks" AS d +WHERE (CAST(d."ParentComplexType" #>> '{Nested,NestedInt}' AS integer)) = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT d."ChildComplexType" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType" +FROM "Drinks" AS d +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT d."ChildComplexType" -> 'Nested' +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType" -> 'Nested' +FROM "Drinks" AS d +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", d."ChildComplexType", d."ChildComplexType" +FROM "Drinks" AS d +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(d."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c + WHERE c."Int" > 59) = 2 +"""); + } + + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlFixture.cs similarity index 87% rename from test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlFixture.cs index 8bae413c1..1db1bc96a 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlFixture.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.InheritanceModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPHInheritanceQueryNpgsqlFixture : TPHInheritanceQueryFixture { @@ -11,7 +11,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con { base.OnModelCreating(modelBuilder, context); - modelBuilder.Entity().HasNoKey().ToSqlQuery(""" + modelBuilder.Entity().HasNoKey().ToSqlQuery( + """ SELECT * FROM "Animals" """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlTest.cs new file mode 100644 index 000000000..a8e9dce45 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceQueryNpgsqlTest.cs @@ -0,0 +1,673 @@ +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPHInheritanceQueryNpgsqlTest(TPHInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPHInheritanceQueryTestBase(fixture, testOutputHelper) +{ + public override async Task Byte_enum_value_constant_used_in_projection(bool async) + { + await base.Byte_enum_value_constant_used_in_projection(async); + + AssertSql( + """ +SELECT CASE + WHEN a."IsFlightless" THEN 0 + ELSE 1 +END +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Can_filter_all_animals(bool async) + { + await base.Can_filter_all_animals(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Name" = 'Great spotted kiwi' +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_include_animals(bool async) + { + await base.Can_include_animals(async); + + AssertSql( + """ +SELECT c."Id", c."Name", a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Countries" AS c +LEFT JOIN "Animals" AS a ON c."Id" = a."CountryId" +ORDER BY c."Name" NULLS FIRST, c."Id" NULLS FIRST +"""); + } + + public override async Task Can_include_prey(bool async) + { + await base.Can_include_prey(async); + + AssertSql( + """ +SELECT a1."Id", a1."CountryId", a1."Discriminator", a1."Name", a1."Species", a1."EagleId", a1."IsFlightless", a1."Group", a0."Id", a0."CountryId", a0."Discriminator", a0."Name", a0."Species", a0."EagleId", a0."IsFlightless", a0."Group", a0."FoundOn" +FROM ( + SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group" + FROM "Animals" AS a + WHERE a."Discriminator" = 'Eagle' + LIMIT 2 +) AS a1 +LEFT JOIN "Animals" AS a0 ON a1."Id" = a0."EagleId" +ORDER BY a1."Id" NULLS FIRST +"""); + } + + public override Task Can_insert_update_delete() + => base.Can_insert_update_delete(); + + public override async Task Can_query_all_animals(bool async) + { + await base.Can_query_all_animals(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_birds(bool async) + { + await base.Can_query_all_birds(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_plants(bool async) + { + await base.Can_query_all_plants(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", p."HasThorns" +FROM "Plants" AS p +ORDER BY p."Species" NULLS FIRST +"""); + } + + public override void FromSql_on_root() + { + base.FromSql_on_root(); + + AssertSql( + """ +select * from "Animals" +"""); + } + + public override void FromSql_on_derived() + { + base.FromSql_on_derived(); + + AssertSql( + """ +SELECT m."Id", m."CountryId", m."Discriminator", m."Name", m."Species", m."EagleId", m."IsFlightless", m."Group" +FROM ( + select * from "Animals" +) AS m +WHERE m."Discriminator" = 'Eagle' +"""); + } + + public override async Task Can_query_all_types_when_shared_column(bool async) + { + await base.Can_query_all_types_when_shared_column(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +"""); + } + + public override async Task Can_query_just_kiwis(bool async) + { + await base.Can_query_just_kiwis(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +LIMIT 2 +"""); + } + + public override async Task Can_query_just_roses(bool async) + { + await base.Can_query_just_roses(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", p."HasThorns" +FROM "Plants" AS p +WHERE p."Genus" = 0 +LIMIT 2 +"""); + } + + public override async Task Can_query_when_shared_column(bool async) + { + await base.Can_query_when_shared_column(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 +LIMIT 2 +""", + // + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."LiltCO2", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 2 +LIMIT 2 +""", + // + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 3 +LIMIT 2 +"""); + } + + public override async Task Can_use_backwards_is_animal(bool async) + { + await base.Can_use_backwards_is_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Can_use_backwards_of_type_animal(bool async) + { + await base.Can_use_backwards_of_type_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Can_use_is_kiwi(bool async) + { + await base.Can_use_is_kiwi(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Can_use_is_kiwi_with_cast(bool async) + { + await base.Can_use_is_kiwi_with_cast(async); + + AssertSql( + """ +SELECT CASE + WHEN a."Discriminator" = 'Kiwi' THEN a."FoundOn" + ELSE 0 +END AS "Value" +FROM "Animals" AS a +"""); + } + + public override async Task Can_use_is_kiwi_in_projection(bool async) + { + await base.Can_use_is_kiwi_in_projection(async); + + AssertSql( + """ +SELECT a."Discriminator" = 'Kiwi' +FROM "Animals" AS a +"""); + } + + public override async Task Can_use_is_kiwi_with_other_predicate(bool async) + { + await base.Can_use_is_kiwi_with_other_predicate(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' AND a."CountryId" = 1 +"""); + } + + public override async Task Can_use_of_type_animal(bool async) + { + await base.Can_use_of_type_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird(bool async) + { + await base.Can_use_of_type_bird(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_first(bool async) + { + await base.Can_use_of_type_bird_first(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +ORDER BY a."Species" NULLS FIRST +LIMIT 1 +"""); + } + + public override async Task Can_use_of_type_bird_predicate(bool async) + { + await base.Can_use_of_type_bird_predicate(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."CountryId" = 1 +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_with_projection(bool async) + { + await base.Can_use_of_type_bird_with_projection(async); + + AssertSql( + """ +SELECT a."EagleId" +FROM "Animals" AS a +"""); + } + + public override async Task Can_use_of_type_kiwi(bool async) + { + await base.Can_use_of_type_kiwi(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Can_use_of_type_kiwi_where_north_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_north_on_derived_property(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' AND a."FoundOn" = 0 +"""); + } + + public override async Task Can_use_of_type_kiwi_where_south_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_south_on_derived_property(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' AND a."FoundOn" = 1 +"""); + } + + public override async Task Can_use_of_type_rose(bool async) + { + await base.Can_use_of_type_rose(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", p."HasThorns" +FROM "Plants" AS p +WHERE p."Genus" = 0 +"""); + } + + public override async Task Member_access_on_intermediate_type_works() + { + await base.Member_access_on_intermediate_type_works(); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +ORDER BY a."Name" NULLS FIRST +"""); + } + + public override void Casting_to_base_type_joining_with_query_type_works() + { + base.Casting_to_base_type_joining_with_query_type_works(); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", m."CountryId", m."Discriminator", m."Name", m."EagleId", m."IsFlightless", m."Group", m."FoundOn" +FROM "Animals" AS a +INNER JOIN ( + Select * from "Animals" +) AS m ON a."Name" = m."Name" +WHERE a."Discriminator" = 'Eagle' +"""); + } + + public override async Task OfType_Union_OfType(bool async) + { + await base.OfType_Union_OfType(async); + + AssertSql(); + } + + public override async Task OfType_Union_subquery(bool async) + { + await base.OfType_Union_subquery(async); + + AssertSql(); + } + + public override Task Setting_foreign_key_to_a_different_type_throws() + => base.Setting_foreign_key_to_a_different_type_throws(); + + public override async Task Subquery_OfType(bool async) + { + await base.Subquery_OfType(async); + + AssertSql( + """ +@p='5' + +SELECT DISTINCT a0."Id", a0."CountryId", a0."Discriminator", a0."Name", a0."Species", a0."EagleId", a0."IsFlightless", a0."FoundOn" +FROM ( + SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."FoundOn" + FROM "Animals" AS a + ORDER BY a."Species" NULLS FIRST + LIMIT @p +) AS a0 +WHERE a0."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Union_entity_equality(bool async) + { + await base.Union_entity_equality(async); + + AssertSql(); + } + + public override async Task Union_siblings_with_duplicate_property_in_subquery(bool async) + { + await base.Union_siblings_with_duplicate_property_in_subquery(async); + + AssertSql(); + } + + public override async Task Is_operator_on_result_of_FirstOrDefault(bool async) + { + await base.Is_operator_on_result_of_FirstOrDefault(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE ( + SELECT a0."Discriminator" + FROM "Animals" AS a0 + WHERE a0."Name" = 'Great spotted kiwi' + LIMIT 1) = 'Kiwi' +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Selecting_only_base_properties_on_base_type(bool async) + { + await base.Selecting_only_base_properties_on_base_type(async); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +"""); + } + + public override async Task Selecting_only_base_properties_on_derived_type(bool async) + { + await base.Selecting_only_base_properties_on_derived_type(async); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +"""); + } + + public override async Task Can_query_all_animal_views(bool async) + { + await base.Can_query_all_animal_views(async); + + AssertSql( + """ +SELECT m."CountryId", m."Discriminator", m."Name", m."EagleId", m."IsFlightless", m."Group", m."FoundOn" +FROM ( + SELECT * FROM "Animals" +) AS m +ORDER BY m."CountryId" NULLS FIRST +"""); + } + + public override async Task Discriminator_used_when_projection_over_derived_type(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type(async); + + AssertSql( + """ +SELECT a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Discriminator_used_when_projection_over_derived_type2(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type2(async); + + AssertSql( + """ +SELECT a."IsFlightless", a."Discriminator" +FROM "Animals" AS a +"""); + } + + public override async Task Discriminator_used_when_projection_over_of_type(bool async) + { + await base.Discriminator_used_when_projection_over_of_type(async); + + AssertSql( + """ +SELECT a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Discriminator_with_cast_in_shadow_property(bool async) + { + await base.Discriminator_with_cast_in_shadow_property(async); + + AssertSql( + """ +SELECT a."Name" AS "Predator" +FROM "Animals" AS a +WHERE 'Kiwi' = a."Discriminator" +"""); + } + + public override async Task Using_is_operator_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE FALSE +"""); + } + + public override async Task Using_is_operator_with_of_type_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_with_of_type_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group" +FROM "Animals" AS a +WHERE FALSE +"""); + } + + public override async Task Using_OfType_on_multiple_type_with_no_result(bool async) + { + await base.Using_OfType_on_multiple_type_with_no_result(async); + + AssertSql(); + } + + public override async Task GetType_in_hierarchy_in_abstract_base_type(bool async) + { + await base.GetType_in_hierarchy_in_abstract_base_type(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Eagle' +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" = 'Kiwi' +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Discriminator", a."Name", a."Species", a."EagleId", a."IsFlightless", a."Group", a."FoundOn" +FROM "Animals" AS a +WHERE a."Discriminator" <> 'Kiwi' +"""); + } + + public override async Task Primitive_collection_on_subtype(bool async) + { + await base.Primitive_collection_on_subtype(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE cardinality(d."Ints") > 0 +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceTableSplittingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceTableSplittingQueryNpgsqlTest.cs new file mode 100644 index 000000000..9f4975fe5 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPHInheritanceTableSplittingQueryNpgsqlTest.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPHInheritanceTableSplittingQueryNpgsqlTest( + TPHInheritanceQueryNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : TPHInheritanceTableSplittingQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 AND d."ChildComplexType_Int" = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."ParentComplexType_Int" = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 AND d."ChildComplexType_Nested_NestedInt" = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."ParentComplexType_Nested_NestedInt" = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE d."Discriminator" = 1 +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT d."Id", d."Discriminator", d."SortIndex", d."CaffeineGrams", d."CokeCO2", d."Ints", d."SugarGrams", d."LiltCO2", d."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", d."ChildComplexType_Int", d."ChildComplexType_UniqueInt", d."ChildComplexType_Nested_NestedInt", d."ChildComplexType_Nested_UniqueInt", d."Tea_ChildComplexType_Int", d."Tea_ChildComplexType_UniqueInt", d."Tea_ChildComplexType_Nested_NestedInt", d."Tea_ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(d."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c + WHERE c."Int" > 59) = 2 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlFixture.cs new file mode 100644 index 000000000..12e359b8f --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlFixture.cs @@ -0,0 +1,7 @@ +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTFiltersInheritanceQueryNpgsqlFixture : TPTInheritanceQueryNpgsqlFixture +{ + public override bool EnableFilters + => true; +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlTest.cs new file mode 100644 index 000000000..a933a72bb --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTFiltersInheritanceQueryNpgsqlTest.cs @@ -0,0 +1,14 @@ +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTFiltersInheritanceQueryNpgsqlTest : TPTFiltersInheritanceQueryTestBase +{ + // ReSharper disable once UnusedParameter.Local + public TPTFiltersInheritanceQueryNpgsqlTest( + TPTFiltersInheritanceQueryNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlFixture.cs similarity index 98% rename from test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlFixture.cs index 40d55c7a7..2e200e3e0 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlFixture.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTGearsOfWarQueryNpgsqlFixture : TPTGearsOfWarQueryRelationalFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlTest.cs similarity index 98% rename from test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlTest.cs index ae0185107..fe2cd7788 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTGearsOfWarQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTGearsOfWarQueryNpgsqlTest.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTGearsOfWarQueryNpgsqlTest : TPTGearsOfWarQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlFixture.cs new file mode 100644 index 000000000..6eff3f829 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlFixture.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTInheritanceJsonQueryNpgsqlFixture : TPTInheritanceJsonQueryRelationalFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory + => NpgsqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlTest.cs new file mode 100644 index 000000000..5410cdc98 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceJsonQueryNpgsqlTest.cs @@ -0,0 +1,143 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTInheritanceJsonQueryNpgsqlTest(TPTInheritanceJsonQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPTInheritanceJsonQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType", c."ChildComplexType" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +WHERE (CAST(c."ChildComplexType" ->> 'Int' AS integer)) = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", c."ChildComplexType", t."ChildComplexType", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE (CAST(d."ParentComplexType" ->> 'Int' AS integer)) = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType", c."ChildComplexType" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +WHERE (CAST(c."ChildComplexType" #>> '{Nested,NestedInt}' AS integer)) = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", c."ChildComplexType", t."ChildComplexType", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE (CAST(d."ParentComplexType" #>> '{Nested,NestedInt}' AS integer)) = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType" +FROM "Drinks" AS d +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType" -> 'Nested' +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType" -> 'Nested' +FROM "Drinks" AS d +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType", c."ChildComplexType", t."ChildComplexType", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(d."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c0 + WHERE c0."Int" > 59) = 2 +"""); + } + + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlFixture.cs similarity index 75% rename from test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlFixture.cs index a3330b63f..9b3bc841b 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlFixture.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTInheritanceQueryNpgsqlFixture : TPTInheritanceQueryFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlTest.cs new file mode 100644 index 000000000..0ba656b30 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceQueryNpgsqlTest.cs @@ -0,0 +1,801 @@ +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTInheritanceQueryNpgsqlTest(TPTInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) + : TPTInheritanceQueryTestBase(fixture, testOutputHelper) +{ + public override async Task Byte_enum_value_constant_used_in_projection(bool async) + { + await base.Byte_enum_value_constant_used_in_projection(async); + + AssertSql( + """ +SELECT CASE + WHEN b."IsFlightless" THEN 0 + ELSE 1 +END +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +INNER JOIN "Kiwi" AS k ON a."Id" = k."Id" +"""); + } + + public override async Task Can_filter_all_animals(bool async) + { + await base.Can_filter_all_animals(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE a."Name" = 'Great spotted kiwi' +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_include_animals(bool async) + { + await base.Can_include_animals(async); + + AssertSql( + """ +SELECT c."Id", c."Name", s."Id", s."CountryId", s."Name", s."Species", s."EagleId", s."IsFlightless", s."Group", s."FoundOn", s."Discriminator" +FROM "Countries" AS c +LEFT JOIN ( + SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' + END AS "Discriminator" + FROM "Animals" AS a + LEFT JOIN "Birds" AS b ON a."Id" = b."Id" + LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" + LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +) AS s ON c."Id" = s."CountryId" +ORDER BY c."Name" NULLS FIRST, c."Id" NULLS FIRST +"""); + } + + public override async Task Can_include_prey(bool async) + { + await base.Can_include_prey(async); + + AssertSql( + """ +SELECT s."Id", s."CountryId", s."Name", s."Species", s."EagleId", s."IsFlightless", s."Group", s0."Id", s0."CountryId", s0."Name", s0."Species", s0."EagleId", s0."IsFlightless", s0."Group", s0."FoundOn", s0."Discriminator" +FROM ( + SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group" + FROM "Animals" AS a + INNER JOIN "Birds" AS b ON a."Id" = b."Id" + INNER JOIN "Eagle" AS e ON a."Id" = e."Id" + LIMIT 2 +) AS s +LEFT JOIN ( + SELECT a0."Id", a0."CountryId", a0."Name", a0."Species", b0."EagleId", b0."IsFlightless", e0."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e0."Id" IS NOT NULL THEN 'Eagle' + END AS "Discriminator" + FROM "Animals" AS a0 + INNER JOIN "Birds" AS b0 ON a0."Id" = b0."Id" + LEFT JOIN "Eagle" AS e0 ON a0."Id" = e0."Id" + LEFT JOIN "Kiwi" AS k ON a0."Id" = k."Id" +) AS s0 ON s."Id" = s0."EagleId" +ORDER BY s."Id" NULLS FIRST +"""); + } + + public override Task Can_insert_update_delete() + => base.Can_insert_update_delete(); + + public override async Task Can_query_all_animals(bool async) + { + await base.Can_query_all_animals(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_birds(bool async) + { + await base.Can_query_all_birds(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_plants(bool async) + { + await base.Can_query_all_plants(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", r."HasThorns", CASE + WHEN r."Species" IS NOT NULL THEN 'Rose' + WHEN d."Species" IS NOT NULL THEN 'Daisy' +END AS "Discriminator" +FROM "Plants" AS p +LEFT JOIN "Daisies" AS d ON p."Species" = d."Species" +LEFT JOIN "Roses" AS r ON p."Species" = r."Species" +ORDER BY p."Species" NULLS FIRST +"""); + } + + public override async Task Can_query_all_types_when_shared_column(bool async) + { + await base.Can_query_all_types_when_shared_column(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +"""); + } + + public override async Task Can_query_just_kiwis(bool async) + { + await base.Can_query_just_kiwis(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +INNER JOIN "Kiwi" AS k ON a."Id" = k."Id" +LIMIT 2 +"""); + } + + public override async Task Can_query_just_roses(bool async) + { + await base.Can_query_just_roses(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", r."HasThorns" +FROM "Plants" AS p +INNER JOIN "Flowers" AS f ON p."Species" = f."Species" +INNER JOIN "Roses" AS r ON p."Species" = r."Species" +LIMIT 2 +"""); + } + + public override async Task Can_query_when_shared_column(bool async) + { + await base.Can_query_when_shared_column(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +LIMIT 2 +""", + // + """ +SELECT d."Id", d."SortIndex", l."LiltCO2", l."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Lilt" AS l ON d."Id" = l."Id" +LIMIT 2 +""", + // + """ +SELECT d."Id", d."SortIndex", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Tea" AS t ON d."Id" = t."Id" +LIMIT 2 +"""); + } + + public override async Task Can_use_backwards_is_animal(bool async) + { + await base.Can_use_backwards_is_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +INNER JOIN "Kiwi" AS k ON a."Id" = k."Id" +"""); + } + + public override async Task Can_use_backwards_of_type_animal(bool async) + { + await base.Can_use_backwards_of_type_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +INNER JOIN "Kiwi" AS k ON a."Id" = k."Id" +"""); + } + + public override async Task Can_use_is_kiwi(bool async) + { + await base.Can_use_is_kiwi(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL +"""); + } + + public override async Task Can_use_is_kiwi_with_cast(bool async) + { + await base.Can_use_is_kiwi_with_cast(async); + + AssertSql( + """ +SELECT CASE + WHEN k."Id" IS NOT NULL THEN k."FoundOn" + ELSE 0 +END AS "Value" +FROM "Animals" AS a +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +"""); + } + + public override async Task Can_use_is_kiwi_in_projection(bool async) + { + await base.Can_use_is_kiwi_in_projection(async); + + AssertSql( + """ +SELECT k."Id" IS NOT NULL +FROM "Animals" AS a +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +"""); + } + + public override async Task Can_use_is_kiwi_with_other_predicate(bool async) + { + await base.Can_use_is_kiwi_with_other_predicate(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL AND a."CountryId" = 1 +"""); + } + + public override async Task Can_use_of_type_animal(bool async) + { + await base.Can_use_of_type_animal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird(bool async) + { + await base.Can_use_of_type_bird(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL OR e."Id" IS NOT NULL +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_first(bool async) + { + await base.Can_use_of_type_bird_first(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL OR e."Id" IS NOT NULL +ORDER BY a."Species" NULLS FIRST +LIMIT 1 +"""); + } + + public override async Task Can_use_of_type_bird_predicate(bool async) + { + await base.Can_use_of_type_bird_predicate(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE a."CountryId" = 1 AND (k."Id" IS NOT NULL OR e."Id" IS NOT NULL) +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Can_use_of_type_bird_with_projection(bool async) + { + await base.Can_use_of_type_bird_with_projection(async); + + AssertSql( + """ +SELECT b."EagleId" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL OR e."Id" IS NOT NULL +"""); + } + + public override async Task Can_use_of_type_kiwi(bool async) + { + await base.Can_use_of_type_kiwi(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL +"""); + } + + public override async Task Can_use_of_type_kiwi_where_north_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_north_on_derived_property(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL AND k."FoundOn" = 0 +"""); + } + + public override async Task Can_use_of_type_kiwi_where_south_on_derived_property(bool async) + { + await base.Can_use_of_type_kiwi_where_south_on_derived_property(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL AND k."FoundOn" = 1 +"""); + } + + public override async Task Can_use_of_type_rose(bool async) + { + await base.Can_use_of_type_rose(async); + + AssertSql( + """ +SELECT p."Species", p."CountryId", p."Genus", p."Name", r."HasThorns", CASE + WHEN r."Species" IS NOT NULL THEN 'Rose' +END AS "Discriminator" +FROM "Plants" AS p +LEFT JOIN "Roses" AS r ON p."Species" = r."Species" +WHERE r."Species" IS NOT NULL +"""); + } + + public override async Task Member_access_on_intermediate_type_works() + { + await base.Member_access_on_intermediate_type_works(); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +INNER JOIN "Kiwi" AS k ON a."Id" = k."Id" +ORDER BY a."Name" NULLS FIRST +"""); + } + + public override async Task OfType_Union_OfType(bool async) + { + await base.OfType_Union_OfType(async); + + AssertSql(); + } + + public override async Task OfType_Union_subquery(bool async) + { + await base.OfType_Union_subquery(async); + + AssertSql(); + } + + public override Task Setting_foreign_key_to_a_different_type_throws() + => base.Setting_foreign_key_to_a_different_type_throws(); + + public override async Task Subquery_OfType(bool async) + { + await base.Subquery_OfType(async); + + AssertSql( + """ +@p='5' + +SELECT DISTINCT s."Id", s."CountryId", s."Name", s."Species", s."EagleId", s."IsFlightless", s."FoundOn", s."Discriminator" +FROM ( + SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' + END AS "Discriminator" + FROM "Animals" AS a + INNER JOIN "Birds" AS b ON a."Id" = b."Id" + LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" + LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" + ORDER BY a."Species" NULLS FIRST + LIMIT @p +) AS s +WHERE s."Discriminator" = 'Kiwi' +"""); + } + + public override async Task Union_entity_equality(bool async) + { + await base.Union_entity_equality(async); + + AssertSql(); + } + + public override async Task Union_siblings_with_duplicate_property_in_subquery(bool async) + { + await base.Union_siblings_with_duplicate_property_in_subquery(async); + + AssertSql(); + } + + public override async Task Is_operator_on_result_of_FirstOrDefault(bool async) + { + await base.Is_operator_on_result_of_FirstOrDefault(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT k0."Id" AS "Id0" + FROM "Animals" AS a0 + LEFT JOIN "Kiwi" AS k0 ON a0."Id" = k0."Id" + WHERE a0."Name" = 'Great spotted kiwi' + LIMIT 1 + ) AS s + WHERE s."Id0" IS NOT NULL) +ORDER BY a."Species" NULLS FIRST +"""); + } + + public override async Task Selecting_only_base_properties_on_base_type(bool async) + { + await base.Selecting_only_base_properties_on_base_type(async); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +"""); + } + + public override async Task Selecting_only_base_properties_on_derived_type(bool async) + { + await base.Selecting_only_base_properties_on_derived_type(async); + + AssertSql( + """ +SELECT a."Name" +FROM "Animals" AS a +INNER JOIN "Birds" AS b ON a."Id" = b."Id" +"""); + } + + public override async Task Can_query_all_animal_views(bool async) + { + await base.Can_query_all_animal_views(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_derived_type(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_derived_type2(bool async) + { + await base.Discriminator_used_when_projection_over_derived_type2(async); + + AssertSql(); + } + + public override async Task Discriminator_used_when_projection_over_of_type(bool async) + { + await base.Discriminator_used_when_projection_over_of_type(async); + + AssertSql(); + } + + public override async Task Discriminator_with_cast_in_shadow_property(bool async) + { + await base.Discriminator_with_cast_in_shadow_property(async); + + AssertSql(); + } + + public override void Using_from_sql_throws() + { + base.Using_from_sql_throws(); + + AssertSql(); + } + + public override async Task Using_is_operator_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL AND e."Id" IS NOT NULL +"""); + } + + public override async Task Using_is_operator_with_of_type_on_multiple_type_with_no_result(bool async) + { + await base.Using_is_operator_with_of_type_on_multiple_type_with_no_result(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", CASE + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL AND e."Id" IS NOT NULL +"""); + } + + public override async Task Using_OfType_on_multiple_type_with_no_result(bool async) + { + await base.Using_OfType_on_multiple_type_with_no_result(async); + + AssertSql(); + } + + public override async Task GetType_in_hierarchy_in_abstract_base_type(bool async) + { + await base.GetType_in_hierarchy_in_abstract_base_type(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE FALSE +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE e."Id" IS NOT NULL +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_reverse(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NOT NULL +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_with_sibling2_not_equal(async); + + AssertSql( + """ +SELECT a."Id", a."CountryId", a."Name", a."Species", b."EagleId", b."IsFlightless", e."Group", k."FoundOn", CASE + WHEN k."Id" IS NOT NULL THEN 'Kiwi' + WHEN e."Id" IS NOT NULL THEN 'Eagle' +END AS "Discriminator" +FROM "Animals" AS a +LEFT JOIN "Birds" AS b ON a."Id" = b."Id" +LEFT JOIN "Eagle" AS e ON a."Id" = e."Id" +LEFT JOIN "Kiwi" AS k ON a."Id" = k."Id" +WHERE k."Id" IS NULL +"""); + } + + public override async Task Primitive_collection_on_subtype(bool async) + { + await base.Primitive_collection_on_subtype(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE cardinality(c."Ints") > 0 +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceTableSplittingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceTableSplittingQueryNpgsqlTest.cs new file mode 100644 index 000000000..6613700e0 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTInheritanceTableSplittingQueryNpgsqlTest.cs @@ -0,0 +1,146 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; + +public class TPTInheritanceTableSplittingQueryNpgsqlTest( + TPTInheritanceQueryNpgsqlFixture fixture, + ITestOutputHelper testOutputHelper) + : TPTInheritanceTableSplittingQueryRelationalTestBase(fixture, testOutputHelper) +{ + public override async Task Filter_on_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +WHERE c."ChildComplexType_Int" = 10 +"""); + } + + public override async Task Filter_on_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE d."ParentComplexType_Int" = 8 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_derived_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_derived_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +WHERE c."ChildComplexType_Nested_NestedInt" = 58 +"""); + } + + public override async Task Filter_on_nested_complex_type_property_on_base_type(bool async) + { + await base.Filter_on_nested_complex_type_property_on_base_type(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE d."ParentComplexType_Nested_NestedInt" = 50 +"""); + } + + public override async Task Project_complex_type_on_derived_type(bool async) + { + await base.Project_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +"""); + } + + public override async Task Project_complex_type_on_base_type(bool async) + { + await base.Project_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +"""); + } + + public override async Task Project_nested_complex_type_on_derived_type(bool async) + { + await base.Project_nested_complex_type_on_derived_type(async); + + AssertSql( + """ +SELECT c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +INNER JOIN "Coke" AS c ON d."Id" = c."Id" +"""); + } + + public override async Task Project_nested_complex_type_on_base_type(bool async) + { + await base.Project_nested_complex_type_on_base_type(async); + + AssertSql( + """ +SELECT d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt" +FROM "Drinks" AS d +"""); + } + + public override async Task Subquery_over_complex_collection(bool async) + { + await base.Subquery_over_complex_collection(async); + + AssertSql( + """ +SELECT d."Id", d."SortIndex", c."CaffeineGrams", c."CokeCO2", c."Ints", c."SugarGrams", l."LiltCO2", l."SugarGrams", t."CaffeineGrams", t."HasMilk", d."ComplexTypeCollection", d."ParentComplexType_Int", d."ParentComplexType_UniqueInt", d."ParentComplexType_Nested_NestedInt", d."ParentComplexType_Nested_UniqueInt", c."ChildComplexType_Int", c."ChildComplexType_UniqueInt", c."ChildComplexType_Nested_NestedInt", c."ChildComplexType_Nested_UniqueInt", t."ChildComplexType_Int", t."ChildComplexType_UniqueInt", t."ChildComplexType_Nested_NestedInt", t."ChildComplexType_Nested_UniqueInt", CASE + WHEN t."Id" IS NOT NULL THEN 'Tea' + WHEN l."Id" IS NOT NULL THEN 'Lilt' + WHEN c."Id" IS NOT NULL THEN 'Coke' +END AS "Discriminator" +FROM "Drinks" AS d +LEFT JOIN "Coke" AS c ON d."Id" = c."Id" +LEFT JOIN "Lilt" AS l ON d."Id" = l."Id" +LEFT JOIN "Tea" AS t ON d."Id" = t."Id" +WHERE ( + SELECT count(*)::int + FROM ROWS FROM (jsonb_to_recordset(d."ComplexTypeCollection") AS ("Int" integer)) WITH ORDINALITY AS c0 + WHERE c0."Int" > 59) = 2 +"""); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); +} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyNoTrackingQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyNoTrackingQueryNpgsqlTest.cs similarity index 90% rename from test/EFCore.PG.FunctionalTests/Query/TPTManyToManyNoTrackingQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyNoTrackingQueryNpgsqlTest.cs index 89c59d3e1..679e18a93 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyNoTrackingQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyNoTrackingQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTManyToManyNoTrackingQueryNpgsqlTest : TPTManyToManyNoTrackingQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlFixture.cs similarity index 95% rename from test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlFixture.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlFixture.cs index 686f9efc0..8c6a25110 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlFixture.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlFixture.cs @@ -1,6 +1,6 @@ using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTManyToManyQueryNpgsqlFixture : TPTManyToManyQueryRelationalFixture { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlTest.cs similarity index 89% rename from test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlTest.cs index e11210b0b..46fc4eede 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTManyToManyQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTManyToManyQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTManyToManyQueryNpgsqlTest : TPTManyToManyQueryRelationalTestBase { diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTRelationshipsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTRelationshipsQueryNpgsqlTest.cs similarity index 91% rename from test/EFCore.PG.FunctionalTests/Query/TPTRelationshipsQueryNpgsqlTest.cs rename to test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTRelationshipsQueryNpgsqlTest.cs index c65693239..ea9dd2077 100644 --- a/test/EFCore.PG.FunctionalTests/Query/TPTRelationshipsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Inheritance/TPTRelationshipsQueryNpgsqlTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.EntityFrameworkCore.Query; +namespace Microsoft.EntityFrameworkCore.Query.Inheritance; public class TPTRelationshipsQueryNpgsqlTest : TPTRelationshipsQueryTestBase diff --git a/test/EFCore.PG.FunctionalTests/Query/NorthwindGroupByQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/NorthwindGroupByQueryNpgsqlTest.cs index 732bff2e0..5ef3dd624 100644 --- a/test/EFCore.PG.FunctionalTests/Query/NorthwindGroupByQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/NorthwindGroupByQueryNpgsqlTest.cs @@ -1190,7 +1190,7 @@ public override async Task OrderBy_Skip_Take_GroupBy_Aggregate(bool async) AssertSql( """ -@p0='500' +@p1='500' @p='80' SELECT max(o0."OrderID") @@ -1198,7 +1198,7 @@ SELECT max(o0."OrderID") SELECT o."OrderID", o."CustomerID" FROM "Orders" AS o ORDER BY o."OrderID" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS o0 GROUP BY o0."CustomerID" """); @@ -1280,8 +1280,8 @@ public override async Task Join_complex_GroupBy_Aggregate(bool async) AssertSql( """ @p='100' -@p1='50' -@p0='10' +@p2='50' +@p1='10' SELECT c0."CustomerID" AS "Key", avg(o0."OrderID"::double precision) AS "Count" FROM ( @@ -1296,7 +1296,7 @@ SELECT c."CustomerID" FROM "Customers" AS c WHERE c."CustomerID" NOT IN ('DRACD', 'FOLKO') ORDER BY c."City" NULLS FIRST - LIMIT @p1 OFFSET @p0 + LIMIT @p2 OFFSET @p1 ) AS c0 ON o0."CustomerID" = c0."CustomerID" GROUP BY c0."CustomerID" """); @@ -1387,9 +1387,9 @@ public override async Task GroupJoin_complex_GroupBy_Aggregate(bool async) AssertSql( """ -@p0='50' +@p1='50' @p='10' -@p1='100' +@p2='100' SELECT o0."CustomerID" AS "Key", avg(o0."OrderID"::double precision) AS "Count" FROM ( @@ -1397,14 +1397,14 @@ SELECT c."CustomerID" FROM "Customers" AS c WHERE c."CustomerID" NOT IN ('DRACD', 'FOLKO') ORDER BY c."City" NULLS FIRST - LIMIT @p0 OFFSET @p + LIMIT @p1 OFFSET @p ) AS c0 INNER JOIN ( SELECT o."OrderID", o."CustomerID" FROM "Orders" AS o WHERE o."OrderID" < 10400 ORDER BY o."OrderDate" NULLS FIRST - LIMIT @p1 + LIMIT @p2 ) AS o0 ON c0."CustomerID" = o0."CustomerID" WHERE o0."OrderID" > 10300 GROUP BY o0."CustomerID" @@ -1612,7 +1612,7 @@ public override async Task GroupBy_aggregate_Pushdown(bool async) AssertSql( """ @p='20' -@p0='4' +@p1='4' SELECT o0."CustomerID" FROM ( @@ -1624,7 +1624,7 @@ ORDER BY o."CustomerID" NULLS FIRST LIMIT @p ) AS o0 ORDER BY o0."CustomerID" NULLS FIRST -OFFSET @p0 +OFFSET @p1 """); } @@ -1635,7 +1635,7 @@ public override async Task GroupBy_aggregate_using_grouping_key_Pushdown(bool as AssertSql( """ @p='20' -@p0='4' +@p1='4' SELECT o0."Key", o0."Max" FROM ( @@ -1647,7 +1647,7 @@ ORDER BY o."CustomerID" NULLS FIRST LIMIT @p ) AS o0 ORDER BY o0."Key" NULLS FIRST -OFFSET @p0 +OFFSET @p1 """); } @@ -1658,7 +1658,7 @@ public override async Task GroupBy_aggregate_Pushdown_followed_by_projecting_Len AssertSql( """ @p='20' -@p0='4' +@p1='4' SELECT length(o0."CustomerID")::int FROM ( @@ -1670,7 +1670,7 @@ ORDER BY o."CustomerID" NULLS FIRST LIMIT @p ) AS o0 ORDER BY o0."CustomerID" NULLS FIRST -OFFSET @p0 +OFFSET @p1 """); } @@ -1681,7 +1681,7 @@ public override async Task GroupBy_aggregate_Pushdown_followed_by_projecting_con AssertSql( """ @p='20' -@p0='4' +@p1='4' SELECT 5 FROM ( @@ -1693,7 +1693,7 @@ ORDER BY o."CustomerID" NULLS FIRST LIMIT @p ) AS o0 ORDER BY o0."CustomerID" NULLS FIRST -OFFSET @p0 +OFFSET @p1 """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs index 773dd5090..7b7ade293 100644 --- a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs @@ -830,6 +830,34 @@ public override async Task Parameter_collection_null_Contains() """); } + public override async Task Parameter_collection_empty_Contains() + { + await base.Parameter_collection_empty_Contains(); + + AssertSql( + """ +@ints={ } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" = ANY (@ints) +"""); + } + + public override async Task Parameter_collection_empty_Join() + { + await base.Parameter_collection_empty_Join(); + + AssertSql( + """ +@p={ } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +INNER JOIN unnest(@p) AS p0(value) ON p."Id" = p0.value +"""); + } + public override async Task Parameter_collection_Contains_with_EF_Constant() { await base.Parameter_collection_Contains_with_EF_Constant(); @@ -881,6 +909,41 @@ public override async Task Parameter_collection_Count_with_huge_number_of_values AssertSql(); } + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations(); + + AssertSql(); + } + + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_same_parameter(); + + AssertSql(); + } + + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + AssertSql(); + } + + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_forced_constants(); + + AssertSql(); + } + + public override async Task Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants() + { + await base.Parameter_collection_Count_with_huge_number_of_values_over_5_operations_mixed_parameters_constants(); + + AssertSql(); + } + // The following test does nothing since we don't override NumberOfValuesForHugeParameterCollectionTests; // the PG parameter limit is huge (ushort), so we don't need to test it. public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values() @@ -890,6 +953,95 @@ public override async Task Parameter_collection_of_ints_Contains_int_with_huge_n AssertSql(); } + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations(); + + AssertSql(); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_same_parameter(); + + AssertSql(); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_2_operations_same_parameter_different_type_mapping(); + + AssertSql(); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_forced_constants(); + + AssertSql(); + } + + public override async Task Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_mixed_parameters_constants() + { + await base.Parameter_collection_of_ints_Contains_int_with_huge_number_of_values_over_5_operations_mixed_parameters_constants(); + + AssertSql(); + } + + public override async Task Static_readonly_collection_List_of_ints_Contains_int() + { + await base.Static_readonly_collection_List_of_ints_Contains_int(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +""", + // + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" NOT IN (10, 999) +"""); + } + + public override async Task Static_readonly_collection_FrozenSet_of_ints_Contains_int() + { + await base.Static_readonly_collection_FrozenSet_of_ints_Contains_int(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +""", + // + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" NOT IN (10, 999) +"""); + } + + public override async Task Static_readonly_collection_ImmutableArray_of_ints_Contains_int() + { + await base.Static_readonly_collection_ImmutableArray_of_ints_Contains_int(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +""", + // + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" NOT IN (10, 999) +"""); + } + [ConditionalFact] // #3012 [MinimumPostgresVersion(14, 0)] // Multiranges were introduced in PostgreSQL 14 public virtual async Task Parameter_collection_of_ranges_Contains() @@ -987,6 +1139,42 @@ public override async Task Column_collection_of_bools_Contains() """); } + public override async Task Contains_on_Enumerable() + { + await base.Contains_on_Enumerable(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +"""); + } + + public override async Task Contains_on_MemoryExtensions() + { + await base.Contains_on_MemoryExtensions(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +"""); + } + + public override async Task Contains_with_MemoryExtensions_with_null_comparer() + { + await base.Contains_with_MemoryExtensions_with_null_comparer(); + + AssertSql( + """ +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" IN (10, 999) +"""); + } + public override async Task Column_collection_Count_method() { await base.Column_collection_Count_method(); @@ -1542,12 +1730,12 @@ public override async Task Parameter_collection_Concat_column_collection() AssertSql( """ -@ints={ '11' +@p={ '11' '111' } (DbType = Object) SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" FROM "PrimitiveCollectionsEntity" AS p -WHERE cardinality(@ints || p."Ints") = 2 +WHERE cardinality(@p || p."Ints") = 2 """); } @@ -1843,6 +2031,20 @@ public override async Task Parameter_collection_in_subquery_Union_another_parame AssertSql(); } + public override async Task Compiled_query_with_uncorrelated_parameter_collection_expression() + { + await base.Compiled_query_with_uncorrelated_parameter_collection_expression(); + + AssertSql( + """ +@ids={ } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE cardinality(@ids) > 0 +"""); + } + public override async Task Parameter_collection_in_subquery_Count_as_compiled_query() { await base.Parameter_collection_in_subquery_Count_as_compiled_query(); @@ -2278,6 +2480,97 @@ public override Task Parameter_collection_of_nullable_structs_Contains_nullable_ => Assert.ThrowsAnyAsync( () => base.Parameter_collection_of_nullable_structs_Contains_nullable_struct_with_nullable_comparer()); + + public override async Task Inline_collection_Contains_with_IEnumerable_EF_Parameter() + { + await base.Inline_collection_Contains_with_IEnumerable_EF_Parameter(); + + AssertSql( + """ +@Select={ '10' +'a' +'aa' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."NullableString" = ANY (@Select) OR (p."NullableString" IS NULL AND array_position(@Select, NULL) IS NOT NULL) +"""); + } + + + public override async Task Parameter_collection_FrozenSet_of_ints_Contains_int() + { + await base.Parameter_collection_FrozenSet_of_ints_Contains_int(); + + AssertSql( + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" = ANY (@ints) +""", + // + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE NOT (p."Int" = ANY (@ints) AND p."Int" = ANY (@ints) IS NOT NULL) +"""); + } + + + public override async Task Parameter_collection_IReadOnlySet_of_ints_Contains_int() + { + await base.Parameter_collection_IReadOnlySet_of_ints_Contains_int(); + + AssertSql( + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" = ANY (@ints) +""", + // + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE NOT (p."Int" = ANY (@ints) AND p."Int" = ANY (@ints) IS NOT NULL) +"""); + } + + public override async Task Parameter_collection_ReadOnlyCollectionWithContains_of_ints_Contains_int() + { + await base.Parameter_collection_ReadOnlyCollectionWithContains_of_ints_Contains_int(); + + AssertSql( + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE p."Int" = ANY (@ints) +""", + // + """ +@ints={ '10' +'999' } (DbType = Object) + +SELECT p."Id", p."Bool", p."Bools", p."DateTime", p."DateTimes", p."Enum", p."Enums", p."Int", p."Ints", p."NullableInt", p."NullableInts", p."NullableString", p."NullableStrings", p."NullableWrappedId", p."NullableWrappedIdWithNullableComparer", p."String", p."Strings", p."WrappedId" +FROM "PrimitiveCollectionsEntity" AS p +WHERE NOT (p."Int" = ANY (@ints) AND p."Int" = ANY (@ints) IS NOT NULL) +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlTest.cs deleted file mode 100644 index c947da605..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/TPCInheritanceQueryNpgsqlTest.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.Query; - -public class TPCInheritanceQueryNpgsqlTest(TPCInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) - : TPCInheritanceQueryTestBase(fixture, testOutputHelper) -{ - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); -} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlTest.cs deleted file mode 100644 index 6e49fc9f3..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/TPHInheritanceQueryNpgsqlTest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.Query; - -public class TPHInheritanceQueryNpgsqlTest(TPHInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) - : TPHInheritanceQueryTestBase(fixture, testOutputHelper); diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlFixture.cs deleted file mode 100644 index 1ce235de0..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlFixture.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.Query; - -public class TPTFiltersInheritanceQuerySqlServerFixture : TPTInheritanceQueryNpgsqlFixture -{ - public override bool EnableFilters - => true; -} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlTest.cs deleted file mode 100644 index cf797747b..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/TPTFiltersInheritanceQueryNpgsqlTest.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.Query; - -public class TPTFiltersInheritanceQuerySqlServerTest : TPTFiltersInheritanceQueryTestBase -{ - // ReSharper disable once UnusedParameter.Local - public TPTFiltersInheritanceQuerySqlServerTest( - TPTFiltersInheritanceQuerySqlServerFixture fixture, - ITestOutputHelper testOutputHelper) - : base(fixture) - { - Fixture.TestSqlLoggerFactory.Clear(); - Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); - } -} diff --git a/test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlTest.cs deleted file mode 100644 index 0639ec896..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/TPTInheritanceQueryNpgsqlTest.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Microsoft.EntityFrameworkCore.Query; - -public class TPTInheritanceQueryNpgsqlTest(TPTInheritanceQueryNpgsqlFixture fixture, ITestOutputHelper testOutputHelper) - : TPTInheritanceQueryTestBase(fixture, testOutputHelper); diff --git a/test/EFCore.PG.FunctionalTests/RuntimeMigrationNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/RuntimeMigrationNpgsqlTest.cs new file mode 100644 index 000000000..7257528d2 --- /dev/null +++ b/test/EFCore.PG.FunctionalTests/RuntimeMigrationNpgsqlTest.cs @@ -0,0 +1,32 @@ +using System.Data.Common; +using Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal; + +namespace Microsoft.EntityFrameworkCore; + +#nullable disable + +public class RuntimeMigrationNpgsqlTest(RuntimeMigrationNpgsqlTest.RuntimeMigrationNpgsqlFixture fixture) + : RuntimeMigrationTestBase(fixture) +{ + protected override Assembly ProviderAssembly + => typeof(NpgsqlDesignTimeServices).Assembly; + + protected override List GetTableNames(DbConnection connection) + { + var tables = new List(); + using var command = connection.CreateCommand(); + command.CommandText = "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'public' AND table_name != '__EFMigrationsHistory'"; + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + tables.Add(reader.GetString(0)); + } + return tables; + } + + public class RuntimeMigrationNpgsqlFixture : RuntimeMigrationFixtureBase + { + protected override ITestStoreFactory TestStoreFactory + => NpgsqlTestStoreFactory.Instance; + } +} diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseCleaner.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseCleaner.cs index 73f624818..26d7efd3a 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseCleaner.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseCleaner.cs @@ -1,6 +1,7 @@ using System.Data.Common; using System.Text; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; +using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Diagnostics.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Scaffolding.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal; @@ -20,10 +21,13 @@ protected override IDatabaseModelFactory CreateDatabaseModelFactory(ILoggerFacto new NpgsqlLoggingDefinitions(), new NullDbContextLogger())); + protected override bool AcceptTable(DatabaseTable table) + => table is not DatabaseView; + protected override bool AcceptIndex(DatabaseIndex index) => false; - public override void Clean(DatabaseFacade facade) + public override void Clean(DatabaseFacade facade, bool createTables = true) { // The following is somewhat hacky // PostGIS creates some system tables (e.g. spatial_ref_sys) which can't be dropped until the extension @@ -48,7 +52,7 @@ public override void Clean(DatabaseFacade facade) } } - base.Clean(facade); + base.Clean(facade, createTables); } private void DropExtensions(NpgsqlConnection conn) @@ -159,13 +163,27 @@ FROM pg_collation coll } protected override string BuildCustomSql(DatabaseModel databaseModel) + { + var sb = new StringBuilder(); + + // Drop views before tables, since views may depend on tables + foreach (var view in databaseModel.Tables.OfType()) + { + sb.Append("DROP VIEW IF EXISTS ") + .Append(_sqlGenerationHelper.DelimitIdentifier(view.Name, view.Schema)) + .Append(" CASCADE;"); + } + // Some extensions create tables (e.g. PostGIS), so we must drop them first. - => databaseModel.GetPostgresExtensions() - .Select(e => _sqlGenerationHelper.DelimitIdentifier(e.Name, e.Schema)) - .Aggregate( - new StringBuilder(), - (builder, s) => builder.Append("DROP EXTENSION ").Append(s).Append(";"), - builder => builder.ToString()); + foreach (var extension in databaseModel.GetPostgresExtensions()) + { + sb.Append("DROP EXTENSION ") + .Append(_sqlGenerationHelper.DelimitIdentifier(extension.Name, extension.Schema)) + .Append(';'); + } + + return sb.ToString(); + } protected override string BuildCustomEndingSql(DatabaseModel databaseModel) => databaseModel.GetPostgresEnums() diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseFacadeExtensions.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseFacadeExtensions.cs index 838c27ab4..159636a2e 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseFacadeExtensions.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlDatabaseFacadeExtensions.cs @@ -2,7 +2,7 @@ public static class NpgsqlDatabaseFacadeExtensions { - public static void EnsureClean(this DatabaseFacade databaseFacade) + public static void EnsureClean(this DatabaseFacade databaseFacade, bool createTables = true) => databaseFacade.CreateExecutionStrategy() - .Execute(databaseFacade, database => new NpgsqlDatabaseCleaner().Clean(database)); + .Execute(databaseFacade, database => new NpgsqlDatabaseCleaner().Clean(database, createTables)); } diff --git a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs index 172704d34..b07fddc2c 100644 --- a/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs +++ b/test/EFCore.PG.FunctionalTests/TestUtilities/NpgsqlTestStore.cs @@ -433,9 +433,9 @@ public static string CreateConnectionString(string name, string? options = null) private static string CreateAdminConnectionString() => CreateConnectionString("postgres"); - public override Task CleanAsync(DbContext context) + public override Task CleanAsync(DbContext context, bool createTables = true) { - context.Database.EnsureClean(); + context.Database.EnsureClean(createTables); return Task.CompletedTask; } } diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs index de95a3610..e67262e84 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs @@ -3,9 +3,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; public class NpgsqlBoolTypeTest(NpgsqlBoolTypeTest.BoolTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +31,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='False' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs index e48ee770d..cceef538f 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs @@ -3,9 +3,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; public class ByteArrayTypeTest(ByteArrayTypeTest.ByteArrayTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = BYTEA E'\\x010203' +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +31,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='0x04050607' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs index 057f204ee..82576efea 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; public class NpgsqlGuidTypeTest(NpgsqlGuidTypeTest.GuidTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = '8f7331d6-cde9-44fb-8611-81fff686f280' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='ae192c36-9004-49b2-b785-8be10d169627' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs index fca9ec380..70648d786 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous; public class StringTypeTest(StringTypeTest.StringTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = 'foo' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='bar' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs index cdedfcb3d..8873536ad 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs @@ -5,9 +5,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Networking; public class NpgsqlInetTypeTest(NpgsqlInetTypeTest.InetTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = INET '192.168.1.1' +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -20,6 +33,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='192.168.1.2' (DbType = Object) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs index 3c1ade733..c88bf8183 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs @@ -5,9 +5,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Networking; public class NpgsqlMacaddrTypeTest(NpgsqlMacaddrTypeTest.MacaddrTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = MACADDR '001422012345' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -20,6 +34,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='001422012346' (DbType = Object) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs index 641d42d7b..a6c10b8cd 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlDecimalTypeTest(NpgsqlDecimalTypeTest.DecimalTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = 30.5 +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='30' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs index 3c9a2acb1..37e582859 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlDoubleTypeTest(NpgsqlDoubleTypeTest.DoubleTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = 30.5 +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='30' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs index d5504e90e..56f3f885d 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlFloatTypeTest(NpgsqlFloatTypeTest.FloatTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = 30.5 +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='30' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs index 482b86bc4..0e06c5d1a 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlIntTypeTest(NpgsqlIntTypeTest.IntTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = -2147483648 +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='2147483647' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs index 921c4635f..95c4f667c 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlLongTypeTest(NpgsqlLongTypeTest.LongTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = -9223372036854775808 +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='9223372036854775807' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs index e7c2f56ce..822e51bcd 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs @@ -3,9 +3,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric; public class NpgsqlShortTypeTest(NpgsqlShortTypeTest.ShortTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = -32768 +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +31,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='32767' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs index df22d978d..7ef9190fe 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs @@ -3,9 +3,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class NpgsqlBoolTypeTest(NpgsqlBoolTypeTest.DateOnlyTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = DATE '2020-01-05' +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +31,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='05/03/2022' (DbType = Date) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs index 95ba4cc72..791a8f2bc 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class DateTimeOffsetTypeTest(DateTimeOffsetTypeTest.DateTimeOffsetTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = TIMESTAMPTZ '2020-01-05T12:30:45+00:00' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='2020-01-05T13:30:45.0000000+00:00' (DbType = DateTime) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs index 57bc0c4ec..90b3609d6 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class DateTimeUnspecifiedTypeTest(DateTimeUnspecifiedTypeTest.DateTimeTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = TIMESTAMP '2020-01-05T12:30:45' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='2022-05-03T00:00:00.0000000' + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs index 8f26b8942..b5a5f3731 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class DateTimeUtcTypeTest(DateTimeUtcTypeTest.DateTimeTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = TIMESTAMPTZ '2020-01-05T12:30:45Z' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='2022-05-03T00:00:00.0000000Z' (DbType = DateTime) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs index e3c978f92..5cd1f9cdf 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs @@ -3,9 +3,23 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class NpgsqlTimeOnlyTypeTest(NpgsqlTimeOnlyTypeTest.TimeOnlyTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = TIME '12:30:45' +LIMIT 2 +"""); + } + + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +32,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='14:00' (DbType = Time) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs index 3093cb533..32528ee64 100644 --- a/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs +++ b/test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs @@ -3,9 +3,22 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal; public class NpgsqlTimeSpanTypeTest(NpgsqlTimeSpanTypeTest.TimeSpanTypeFixture fixture, ITestOutputHelper testOutputHelper) : RelationalTypeTestBase(fixture, testOutputHelper) { - public override async Task Equality_in_query() + public override async Task Equality_in_query_with_constant() { - await base.Equality_in_query(); + await base.Equality_in_query_with_constant(); + + AssertSql( + """ +SELECT t."Id", t."OtherValue", t."Value" +FROM "TypeEntity" AS t +WHERE t."Value" = INTERVAL '12:30:45' +LIMIT 2 +"""); + } + + public override async Task Equality_in_query_with_parameter() + { + await base.Equality_in_query_with_parameter(); AssertSql( """ @@ -18,6 +31,20 @@ LIMIT 2 """); } + public override async Task SaveChanges() + { + await base.SaveChanges(); + + AssertSql( + """ +@p1='1' +@p0='14:00:00' (DbType = Object) + +UPDATE "TypeEntity" SET "Value" = @p0 +WHERE "Id" = @p1; +"""); + } + #region JSON public override async Task Query_property_within_json() diff --git a/test/EFCore.PG.FunctionalTests/UpdatesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/UpdatesNpgsqlTest.cs index 87e2bc634..b634de83a 100644 --- a/test/EFCore.PG.FunctionalTests/UpdatesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/UpdatesNpgsqlTest.cs @@ -47,7 +47,7 @@ public override void Identifiers_are_generated_correctly() "ExtraPropertyWithAnExtremelyLongAndOverlyConvolutedNameThatIsU~", entityType2.GetProperties().ElementAt(1).GetColumnName(StoreObjectIdentifier.Table(entityType2.GetTableName()!))); Assert.Equal( - "ExtraPropertyWithAnExtremelyLongAndOverlyConvolutedNameThatIs~1", + "LoginEntityTypeWithAnExtremelyLongAndOverlyConvolutedNameThatI~", entityType2.GetProperties().ElementAt(2).GetColumnName(StoreObjectIdentifier.Table(entityType2.GetTableName()!))); Assert.Equal( "IX_LoginEntityTypeWithAnExtremelyLongAndOverlyConvolutedNameT~1",