diff --git a/Directory.Packages.props b/Directory.Packages.props index b6310ef70d..68d13cb6e0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,8 +1,8 @@ - 11.0.0-preview.4.26210.110 - 11.0.0-preview.4.26210.110 - 11.0.0-preview.4.26210.110 + 11.0.0-preview.4.26215.121 + 11.0.0-preview.4.26215.121 + 11.0.0-preview.4.26215.121 10.0.0 diff --git a/src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs b/src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs index a79ae8bc36..6364227f24 100644 --- a/src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs +++ b/src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs @@ -11,8 +11,6 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal; /// public class NpgsqlHistoryRepository : HistoryRepository, IHistoryRepository { - private IModel? _model; - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -111,7 +109,9 @@ protected override IReadOnlyList GetCreateCommands() // Note that the approach in EF is to remove specific conventions (e.g. DbSetFindingConvention), but we don't want to hardcode // specific conventions here; for example, the NetTopologySuite plugin has its NpgsqlNetTopologySuiteExtensionAddingConvention // which adds PostGIS. So we just filter out the annotations on the operations themselves. +#pragma warning disable EF1001 // Internal EF Core API usage. var model = EnsureModel(); +#pragma warning restore EF1001 // Internal EF Core API usage. var operations = Dependencies.ModelDiffer.GetDifferences(null, model.GetRelationalModel()); @@ -135,30 +135,6 @@ protected override IReadOnlyList GetCreateCommands() return Dependencies.MigrationsSqlGenerator.Generate(operations, model); } - // Copied as-is from EF's HistoryRepository, since it's private (see https://github.com/dotnet/efcore/issues/34991) - private IModel EnsureModel() - { - if (_model == null) - { - var conventionSet = Dependencies.ConventionSetBuilder.CreateConventionSet(); - - conventionSet.Remove(typeof(DbSetFindingConvention)); - conventionSet.Remove(typeof(RelationalDbFunctionAttributeConvention)); - - var modelBuilder = new ModelBuilder(conventionSet); - modelBuilder.Entity(x => - { - ConfigureTable(x); - x.ToTable(TableName, TableSchema); - }); - - _model = Dependencies.ModelRuntimeInitializer.Initialize( - (IModel)modelBuilder.Model, designTime: true, validationLogger: null); - } - - return _model; - } - bool IHistoryRepository.CreateIfNotExists() { // In PG, doing CREATE TABLE IF NOT EXISTS isn't concurrency-safe, and can result a "duplicate table" error or in a unique diff --git a/test/EFCore.PG.FunctionalTests/JsonTypesNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/JsonTypesNpgsqlTest.cs index 480012bd23..7446bed8cd 100644 --- a/test/EFCore.PG.FunctionalTests/JsonTypesNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/JsonTypesNpgsqlTest.cs @@ -155,14 +155,14 @@ public override Task Can_read_write_nullable_TimeSpan_JSON_values(string? value, // Cannot override since the base test contains [InlineData] attributes which still apply, and which contain data we need // to override. See Can_read_write_nullable_TimeSpan_JSON_values_npgsql instead. // TODO: Implement Can_read_write_collection_of_TimeSpan_JSON_values_npgsql - public override Task Can_read_write_collection_of_TimeSpan_JSON_values() + public override Task Can_read_write_collection_of_TimeSpan_JSON_values(string expected) => Task.CompletedTask; // Cannot override since the base test contains [InlineData] attributes which still apply, and which contain data we need // to override. See Can_read_write_nullable_TimeSpan_JSON_values_npgsql instead. // TODO: Implement Can_read_write_collection_of_nullable_TimeSpan_JSON_values_npgsql - public override Task Can_read_write_collection_of_nullable_TimeSpan_JSON_values() - => Task.CompletedTask; + public override Task Can_read_write_collection_of_nullable_TimeSpan_JSON_values(string expected) + => Task.CompletedTask; #endregion TimeSpan diff --git a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs index f930bc0b3e..ff2d3a56ab 100644 --- a/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/PrimitiveCollectionsQueryNpgsqlTest.cs @@ -2355,6 +2355,63 @@ public override async Task Project_inline_collection_with_Concat() AssertSql(); } + public override async Task Parameter_collection_of_enum_Cast_from_different_enum_type(ParameterTranslationMode mode) + { + await base.Parameter_collection_of_enum_Cast_from_different_enum_type(mode); + + switch (mode) + { + case ParameterTranslationMode.Constant: + { + AssertSql( + """ +SELECT t."Id" +FROM "TestEntity38008" AS t +WHERE EXISTS ( + SELECT 1 + FROM (VALUES (2::int)) AS f("Value") + WHERE f."Value" = t."Status") +"""); + break; + } + + case ParameterTranslationMode.Parameter: + { + AssertSql( + """ +@filter={ '2' } (DbType = Object) + +SELECT t."Id" +FROM "TestEntity38008" AS t +WHERE EXISTS ( + SELECT 1 + FROM unnest(@filter) AS f(value) + WHERE f.value = t."Status") +"""); + break; + } + + case ParameterTranslationMode.MultipleParameters: + { + AssertSql( + """ +@filter1='2' + +SELECT t."Id" +FROM "TestEntity38008" AS t +WHERE EXISTS ( + SELECT 1 + FROM (VALUES (@filter1)) AS f("Value") + WHERE f."Value" = t."Status") +"""); + break; + } + + default: + throw new NotImplementedException(); + } + } + public override async Task Nested_contains_with_Lists_and_no_inferred_type_mapping() { await base.Nested_contains_with_Lists_and_no_inferred_type_mapping(); diff --git a/test/EFCore.PG.FunctionalTests/Query/Translations/Temporal/DateTimeOffsetTranslationsNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/Translations/Temporal/DateTimeOffsetTranslationsNpgsqlTest.cs index 48a27eeb58..44b37ab6be 100644 --- a/test/EFCore.PG.FunctionalTests/Query/Translations/Temporal/DateTimeOffsetTranslationsNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/Translations/Temporal/DateTimeOffsetTranslationsNpgsqlTest.cs @@ -139,6 +139,34 @@ SELECT CAST(b."DateTimeOffset" AT TIME ZONE 'UTC' AS time) """); } + public override async Task DateTime() + { + await base.DateTime(); + + AssertSql( + """ +SELECT b."Id", b."Bool", b."Byte", b."ByteArray", b."DateOnly", b."DateTime", b."DateTimeOffset", b."Decimal", b."Double", b."Enum", b."FlagsEnum", b."Float", b."Guid", b."Int", b."Long", b."Short", b."String", b."TimeOnly", b."TimeSpan" +FROM "BasicTypesEntities" AS b +WHERE b."DateTimeOffset" AT TIME ZONE 'UTC' = TIMESTAMP '1998-05-04T15:30:10' +"""); + } + + // The base test compares DateTimeOffset.UtcDateTime with an Unspecified DateTime, which Npgsql can't generate as a timestamptz literal + public override Task UtcDateTime() + => Assert.ThrowsAsync(() => base.UtcDateTime()); + + public override async Task LocalDateTime() + { + await base.LocalDateTime(); + + AssertSql( + """ +SELECT b."Id", b."Bool", b."Byte", b."ByteArray", b."DateOnly", b."DateTime", b."DateTimeOffset", b."Decimal", b."Double", b."Enum", b."FlagsEnum", b."Float", b."Guid", b."Int", b."Long", b."Short", b."String", b."TimeOnly", b."TimeSpan" +FROM "BasicTypesEntities" AS b +WHERE b."DateTimeOffset"::timestamp > TIMESTAMP '1999-01-01T00:00:00' +"""); + } + public override async Task AddYears() { await base.AddYears(); @@ -222,6 +250,15 @@ public override Task ToUnixTimeMilliseconds() public override Task ToUnixTimeSecond() => AssertTranslationFailed(() => base.ToUnixTimeSecond()); + public override Task ToOffset() + => AssertTranslationFailed(() => base.ToOffset()); + + public override Task Ctor_DateTime() + => AssertTranslationFailed(() => base.Ctor_DateTime()); + + public override Task Ctor_DateTime_TimeSpan() + => AssertTranslationFailed(() => base.Ctor_DateTime_TimeSpan()); + public override async Task Milliseconds_parameter_and_constant() { await base.Milliseconds_parameter_and_constant();