You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.0 KiB
4.0 KiB
PostgreSQL DateTime 时间戳问题修复总结
问题描述
在PostgreSQL数据库中,当使用timestamp with time zone
类型时,只支持UTC时间的DateTime值。错误信息:
Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported.
问题分析
1. 根本原因
- PostgreSQL的
timestamp with time zone
类型要求DateTime的Kind必须是UTC - 代码中虽然使用了
DateTime.UtcNow
,但实体配置中没有明确指定数据库列类型 - 响应类中使用了
DateTime.UtcNow
而不是从实体中获取的时间
2. 问题位置
- 实体配置类:缺少
.HasColumnType("timestamp with time zone")
配置 - 响应构建:使用了
DateTime.UtcNow
而不是实体的时间字段
修复方案
1. 修复的实体配置类
Device相关
- ✅
ProtocolVersionConfiguration
- ✅
CellularDeviceConfiguration
Identity相关
- ✅
AppRoleConfiguration
- ✅
AppUserConfiguration
其他
- ✅
BaseEntityConfiguration
- ✅
PermissionConfiguration
- ✅
LoginLogConfiguration
2. 修复的CommandHandler响应
ProtocolVersion相关
- ✅
UpdateProtocolVersionCommandHandler
:使用existingProtocolVersion.UpdatedAt
Device相关
- ✅
UpdateDeviceCommandHandler
:使用existingDevice.UpdatedAt
3. 修复内容
实体配置类修复
// 修复前
builder.Property(e => e.CreatedAt)
.IsRequired()
.HasComment("创建时间");
// 修复后
builder.Property(e => e.CreatedAt)
.IsRequired()
.HasColumnType("timestamp with time zone")
.HasComment("创建时间");
响应构建修复
// 修复前
UpdatedAt = DateTime.UtcNow
// 修复后
UpdatedAt = existingEntity.UpdatedAt
修复的字段类型
1. 时间戳字段
CreatedAt
/CreatedTime
:创建时间UpdatedAt
/ModifiedTime
:更新时间LastLoginTime
:最后登录时间LoginTime
:登录时间ReleaseDate
:发布日期
2. 数据库类型
- PostgreSQL:
timestamp with time zone
- 确保所有DateTime字段都使用UTC时间
最佳实践
1. 时间处理原则
// ✅ 正确:使用UTC时间
DateTime.UtcNow
// ❌ 错误:使用本地时间
DateTime.Now
// ❌ 错误:使用未指定Kind的时间
new DateTime(2024, 1, 1)
2. 实体配置
// ✅ 正确:明确指定PostgreSQL时间戳类型
builder.Property(e => e.CreatedAt)
.HasColumnType("timestamp with time zone");
// ❌ 错误:依赖默认类型推断
builder.Property(e => e.CreatedAt);
3. 响应构建
// ✅ 正确:使用实体的时间字段
response.UpdatedAt = entity.UpdatedAt;
// ❌ 错误:重新生成时间
response.UpdatedAt = DateTime.UtcNow;
数据库迁移
1. 现有数据库
如果数据库中已有数据,需要确保:
- 所有DateTime字段都存储为UTC时间
- 列类型为
timestamp with time zone
2. 新数据库
- 实体配置会自动生成正确的列类型
- 所有时间字段都会使用UTC时间
验证方法
1. 代码验证
// 检查DateTime.Kind
if (entity.CreatedAt.Kind != DateTimeKind.Utc)
{
throw new InvalidOperationException("DateTime must be UTC");
}
2. 数据库验证
-- 检查列类型
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'your_table'
AND column_name LIKE '%time%';
-- 检查时间值
SELECT created_at, updated_at
FROM your_table
LIMIT 5;
总结
这次修复确保了:
- 数据类型一致性:所有DateTime字段都使用PostgreSQL的
timestamp with time zone
类型 - 时间标准统一:所有时间都使用UTC标准
- 配置明确性:实体配置中明确指定了数据库列类型
- 响应准确性:响应中使用实体的实际时间而不是重新生成的时间
这种修复方式为整个系统提供了统一的时间处理标准,确保了与PostgreSQL数据库的完全兼容性。