You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 7+PostgreSQL:含时区时间戳为主键时无法更新记录

解决PostgreSQL timestamp with time zone作为主键时EF Core更新的时区问题

问题根源

Npgsql.EntityFrameworkCore.PostgreSQL默认会将PostgreSQL的timestamp with time zone类型转换为本地时区的DateTime(DateTimeKind.Local)。当你用UTC时间查询到实体后,实体的Timestamp字段会被自动转为本地时间;更新时EF Core会用这个本地时间去匹配数据库中存储的UTC主键值,导致无法找到对应记录,最终抛出DbUpdateConcurrencyException。

解决方案

1. 全局配置Npgsql使用UTC处理时区时间

在DbContext配置中添加UseUtcDateTime()选项,强制Npgsql将所有timestamp with time zone类型字段以UTC格式的DateTime(DateTimeKind.Utc)读取和写入:

DbContext内配置:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseNpgsql("你的数据库连接字符串", 
        builder => builder.UseUtcDateTime());
}

Program.cs/Startup.cs配置:

builder.Services.AddDbContext<YourDbContext>(options =>
    options.UseNpgsql(
        builder.Configuration.GetConnectionString("YourConnectionString"),
        npgsqlOptions => npgsqlOptions.UseUtcDateTime()));

配置后,查询到的实体Timestamp字段的DateTimeKind会保持为Utc,更新时生成的SQL会使用UTC时间匹配主键,避免时区不匹配问题。

2. 确保实体属性的时区一致性(可选)

在实体类中可以添加逻辑,确保Timestamp属性始终被设置为UTC时间,避免意外的时区转换:

public class MyTable
{
    public long SiteId { get; set; }
    public DateTime Timestamp { get; set; }
    public float Energy { get; set; }

    // 强制设置UTC时间的方法
    public void SetUtcTimestamp(DateTime timestamp)
    {
        Timestamp = DateTime.SpecifyKind(timestamp, DateTimeKind.Utc);
    }
}

3. 使用批量更新优化逻辑(推荐)

避免先查询实体再更新的额外开销,直接使用EF Core的ExecuteUpdate生成原生更新SQL,跳过实体加载环节,从根源上避免时区转换问题:

var targetTimestamp = new DateTime(2023, 3, 12, 12, 13, 14, DateTimeKind.Utc);
var updatedRows = context.MyTable
    .Where(t => t.SiteId == 884524 && t.Timestamp == targetTimestamp)
    .ExecuteUpdate(t => t.SetProperty(e => e.Energy, 15));

这种方式不会加载实体到内存,直接在数据库层面执行更新,性能更高且无时区转换风险。


内容的提问来源于stack exchange,提问作者jokr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:52:59