thu*_*nch 4 c# postgresql datetime entity-framework-core
我有一个使用 nuget 包的 .Net6 控制台应用程序:
我使用 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
);
Run Code Online (Sandbox Code Playgroud)
我的 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; }
}
Run Code Online (Sandbox Code Playgroud)
从命令行使用 psql 命令运行 .sql 文件后。我检查 pgAdmin 4 并看到
确认列类型是没有时区的时间戳。然而,当我通过创建新消息时
using var context = new MessageContext();
context.Messages.Add(new Msg
{
MessageType = message.GetType()
.FullName,
Message = message.ToString()
});
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
保存更改时,我收到异常
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)
Run Code Online (Sandbox Code Playgroud)
看起来非常矛盾,因为它设置时没有时区,并且在创建消息时使用本地时区类型实例化“时间”属性。如果我将其切换为“DateTime.UtcNow”而不是“DateTime.Now”,它就可以工作。我不明白为什么当我将其设置为“无时区的时间戳”时它会抛出异常。显然,一个简单的解决方案是仅使用 utc 时间,但无论如何,为什么在知道详细信息的情况下抛出异常?
UTC 时间戳已与非 UTC 时间戳完全分离,与 PostgreSQL 类型保持一致。前者由带时区的时间戳和类型为 UTC 的日期时间表示,后者由不带时区的时间戳和类型为本地或未指定的日期时间表示。建议尽可能使用 UTC 时间戳。
解决方案 1:启用 6.0 之前的行为
MessageContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
Run Code Online (Sandbox Code Playgroud)
解决方案2:使用DateTimeOffset
public DateTime Time { get; set; } = DateTimeOffset.Now;
Run Code Online (Sandbox Code Playgroud)
关于 DateTimeOffset 与 DateTime 的优秀文章
| 归档时间: |
|
| 查看次数: |
14283 次 |
| 最近记录: |