DB creation fails: "'timestamp without time zone' literal cannot be generated for a UTC DateTime"
See original GitHub issueAfter upgrading the Npgsql package from 5.0.3 to 6.0.0, it was no longer possible for us to create a new database using DbContext.Context.Migrate()
because the following exception would occur:
System.InvalidCastException : 'timestamp without time zone' literal cannot be generated for a UTC DateTime
Stack Trace:
NpgsqlTimestampTypeMapping.GenerateLiteralCore(Object value)
NpgsqlTimestampTypeMapping.GenerateNonNullSqlLiteral(Object value)
MigrationsSqlGenerator.DefaultValue(Object defaultValue, String defaultValueSql, String columnType, MigrationCommandListBuilder builder)
NpgsqlMigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, ColumnOperation operation, IModel model, MigrationCommandListBuilder builder)
MigrationsSqlGenerator.ColumnDefinition(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder)
MigrationsSqlGenerator.Generate(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder, Boolean terminate)
NpgsqlMigrationsSqlGenerator.Generate(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder, Boolean terminate)
<.cctor>b__83_0(MigrationsSqlGenerator g, MigrationOperation o, IModel m, MigrationCommandListBuilder b)
MigrationsSqlGenerator.Generate(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder)
MigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model, MigrationsSqlGenerationOptions options)
NpgsqlMigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model, MigrationsSqlGenerationOptions options)
Migrator.GenerateUpSql(Migration migration, MigrationsSqlGenerationOptions options)
<>c__DisplayClass16_2.<GetMigrationCommandLists>b__2()
Migrator.Migrate(String targetMigration)
RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)
DbGlobals.UpgradeOrCreateDatabase(Action`1 postUpgradeAction, String connectionString) line 83
Here is a zip file with a small solution that reproduces the problem.
This is a ridiculously pared-down version of our database code; it turned out that none of the actual entity classes were needed to reproduce this. Instead, only the migrations were needed.
While debugging, I was very surprised to find out that the BuildTargetModel
method of every single migration is called. This behavior (presumably driven by EF Core) seems completely superfluous, since the main DbContextModelSnapshot
contains a complete model and would allow the final database schema to be created directly, without running any migrations.
I mention this because the exception occurs after AddLastUpdatedDates.BuildTargetModel
is called, and the final migration UpgradeNpgsqlToV6.BuildTargetModel
is not called. If I delete the second-to-last migration, then the last migration is called*… so, I think efcore.pg is choking on something in that second-to-last migration. The exception still occurs if all the other migrations are removed, so I’ve deleted all migrations except the first one, the last one and the second-to-last one.
(* and then there is an exception about “column “last_updated” … does not exist’” but I assume that’s because I stripped out all the other migrations along with all the actual C# entity objects)
I don’t know how to see the npg source code or local variables in my debugger, so I hope you guys can figure out what’s causing this.
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (4 by maintainers)
The problem here is that you have UTC DateTimes as default values for columns of type
timestamp without time zone
; the new 6.0 timestamp behavior strictly enforces the UTC/non-UTC distinction - only non-UTC DateTimes can be inserted intotimestamp without time zone
, and only UTC DateTimes can be inserted intotimestamp with time zone
.I have some possible ideas on how to allow existing migration code to continue working even in 6.0; but the best way around this is currently to go over the existing code and to change the DateTime Kind to correspond to the column type. Specifically for the columns added in the AddLastUpdatedDates migration, this means changing their default values from DateTimeKind.Utc to DateTimeKind.Unspecified. If these columns actually hold UTC data, then after the migration code is fixed, I recommend changing them from
timestamp without time zone
totimestamp with time zone
, as that’s the proper PostgreSQL type for UTC data (see the migration guide for this).If you’d rather not address this right away, you also have the option of using the legacy timestamp behavior via the flag, as detailed in the release notes.
@qwertie thanks for the detailed info - I’ll take a look at this in the coming days.