.net postgres EF core Cannot write DateTime with Kind=Local to PostgreSQL type 'timestamp with time zone'

9w11ddsr  于 5个月前  发布在  PostgreSQL
关注(0)|答案(2)|浏览(90)

我有一个使用nuget包的.Net6控制台应用程序:

  • Microsoft. Website FrameworkCore,版本6.0.8
  • “Npgsql. martyFrameworkCore.PostgreSQL,版本6.0.6”
  • Npgsql,版本6.0.6

我正在使用postgres 14.4,因为它安装并用于运行脚本等。
我运行了一个名为“RightTables.sql”的.sql脚本,如下所示:

create table if not exists "Messages" (
    "Id" uuid primary key,
    "Time" timestamp without time zone,
    "MessageType" text,
    "Message" text
);

字符串
我的EF核心上下文看起来像这样

namespace Database;

public class MessageContext : DbContext
{
  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {
    var dbConfig = Configurer.Config.MessageDbConfig;
    optionsBuilder.UseNpgsql(new NpgsqlConnectionStringBuilder
      {
        Database = dbConfig.DbName,
        Username = dbConfig.Username,
        Password = dbConfig.Password,
        Host = dbConfig.Host,
        Port = dbConfig.Port,
        Pooling = dbConfig.Pooling
      }.ConnectionString,
     optionsBuilder => optionsBuilder.SetPostgresVersion(Version.Parse("14.4")));

    base.OnConfiguring(optionsBuilder);
  }

  public DbSet<Msg> Messages { get; set; }
}

public class Msg
{
  public Guid Id { get; set; } = Guid.NewGuid();
  public DateTime Time { get; set; } = DateTime.Now;
  public string MessageType { get; set; }
  public string Message { get; set; }
}


在使用命令行中的psql命令运行.sql文件后,我检查pgAdmin 4并查看

确认列类型是没有时区的时间戳。然而,当我通过

using var context = new MessageContext();
    context.Messages.Add(new Msg
    {
      MessageType = message.GetType()
        .FullName,
      Message = message.ToString()
    });
    context.SaveChanges();


当保存更改时,我得到异常

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> System.InvalidCastException: Cannot write DateTime with Kind=Local to PostgreSQL type 'timestamp with time zone', only UTC is supported. Note that it's not possible to mix DateTimes with different Kinds in an array/range. See the Npgsql.EnableLegacyTimestampBehavior AppContext switch to enable legacy behavior.
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.ValidateAndGetLength(DateTime value, NpgsqlParameter parameter)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.ValidateObjectAndGetLength(Object value, NpgsqlLengthCache& lengthCache, NpgsqlParameter parameter)
   at Npgsql.NpgsqlParameter.ValidateAndGetLength()
   at Npgsql.NpgsqlParameterCollection.ValidateAndBind(ConnectorTypeMapper typeMapper)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)


看起来非常矛盾,因为它是没有时区设置的,当创建Msg时,它会示例化“Time”属性与本地时区类型。如果我将其切换到“DateTime.UtcNow”而不是“DateTime.Now”,它就可以工作了。我不明白为什么当我将其设置为“timestamp without time zone”时会抛出异常。显然,一个简单的解决方案是只使用utc time,但无论如何,为什么在知道细节的情况下抛出异常?

zbdgwd5y

zbdgwd5y1#

npgsql 6.0重大更改
UTC时间戳已经与非UTC时间戳明确分离,与PostgreSQL类型保持一致。前者由带时区的时间戳和带类型UTC的日期时间表示,后者由不带时区的时间戳和带类型本地或未指定的日期时间表示。建议尽可能使用UTC时间戳。

**方案一:**启用6.0之前的行为

MessageContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

字符串

**方案二:**使用DateTimeOffset

public DateTime Time { get; set; } = DateTimeOffset.Now;


Excellent article for DateTimeOffset vs DateTime

7rfyedvj

7rfyedvj2#

只需将此行添加到启动或程序

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

字符串

相关问题