簡體   English   中英

.net postgres EF 核心無法將 Kind=Local 的 DateTime 寫入 PostgreSQL 類型“帶時區的時間戳”

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

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

  • “Microsoft.EntityFrameworkCore,版本 6.0.8”
  • “Npgsql.EntityFrameworkCore.PostgreSQL,版本 6.0.6”
  • “Npgsql,版本 6.0.6”

我正在使用 postgres 14.4 作為安裝並用於運行腳本等。
我運行一個名為“createTables.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 時使用本地時區類型實例化“時間”屬性。 如果我將它切換到“DateTime.UtcNow”而不是“DateTime.Now”,它可以工作。 當我將其設置為“沒有時區的時間戳”時,我不明白為什么它會引發異常。 顯然,一個簡單的解決方案是只使用 UTC 時間,但無論如何,為什么知道細節會拋出異常?

npgsql 6.0 重大更改

UTC 時間戳已與非 UTC 時間戳完全分開,與 PostgreSQL 類型保持一致。 前者用帶時區的時間戳和帶 UTC 種類的 DateTime 表示,后者用不帶時區的時間戳和帶本地或未指定種類的 DateTime 表示。 建議盡可能使用 UTC 時間戳。

解決方案 1:啟用 6.0 之前的行為

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

解決方案 2:使用DateTimeOffset

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

DateTimeOffset vs DateTime 的優秀文章

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM