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

在EF Core的PostgreSQL中设置仅允许Kind.Unspecified的DateTime列

问题:如何让Npgsql的DateTime范围列仅支持Kind.Unspecified类型

我定义了如下数据库列:

[MaxLength(10)]
[Required]
public List<NpgsqlRange<System.DateTime>> Dates { get; set; }

如何设置使其仅允许Kind.Unspecified类型?插入数据时我遇到以下错误:

System.InvalidCastException : Cannot write DateTime with Kind=Unspecified 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.

我看到的所有解决方案都是使用Npgsql.EnableLegacyTimestampBehavior,但这是让UTC列允许未指定类型,我并不需要这个,而是希望该列强类型为未指定类型。另外,当我启用EnableLegacyTimestampBehavior时,数据会以带"+12"的UTC格式存储到PostgreSQL中,这不是我想要的。


解决方案

1. 显式指定PostgreSQL列类型为不带时区的范围数组

问题根源是Npgsql默认将List<NpgsqlRange<DateTime>>映射为PostgreSQL的tstzrange[](带时区的时间范围数组),这种类型要求DateTime必须是UTC。我们需要手动指定列类型为tsrange[](不带时区的时间范围数组),对应.NET的DateTimeKind.Unspecified。

在DbContext的OnModelCreating方法中配置:

modelBuilder.Entity<你的实体类>()
    .Property(e => e.Dates)
    .HasColumnType("tsrange[]") // 指定不带时区的时间范围数组类型
    .HasConversion(
        // 写入时确保DateTime为Unspecified
        v => v.Select(r => new NpgsqlRange<DateTime>(
            r.Start.HasValue ? DateTime.SpecifyKind(r.Start.Value, DateTimeKind.Unspecified) : null,
            r.End.HasValue ? DateTime.SpecifyKind(r.End.Value, DateTimeKind.Unspecified) : null
        )).ToList(),
        // 读取时确保返回的DateTime为Unspecified
        v => v.Select(r => new NpgsqlRange<DateTime>(
            r.Start.HasValue ? DateTime.SpecifyKind(r.Start.Value, DateTimeKind.Unspecified) : null,
            r.End.HasValue ? DateTime.SpecifyKind(r.End.Value, DateTimeKind.Unspecified) : null
        )).ToList()
    )
    .IsRequired()
    .HasMaxLength(10);

2. 在实体层添加类型验证(可选)

为了避免意外传入非Unspecified类型的DateTime,可以在属性的setter中添加验证逻辑:

private List<NpgsqlRange<DateTime>> _dates;

[MaxLength(10)]
[Required]
public List<NpgsqlRange<DateTime>> Dates
{
    get => _dates;
    set
    {
        if (value == null)
            throw new ArgumentNullException(nameof(Dates));
            
        foreach (var range in value)
        {
            if (range.Start.HasValue && range.Start.Value.Kind != DateTimeKind.Unspecified)
                throw new ArgumentException("日期范围的起始时间必须为Unspecified类型");
            if (range.End.HasValue && range.End.Value.Kind != DateTimeKind.Unspecified)
                throw new ArgumentException("日期范围的结束时间必须为Unspecified类型");
        }
        
        _dates = value;
    }
}

3. 避免全局强制UTC配置

确保没有在项目中设置全局强制UTC的Npgsql配置,比如:

// 不要添加这行代码
// NpgsqlConnection.GlobalTypeMapper.MapDateTime(DateTimeKind.Utc);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:51:26