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.

163 lines
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. 问题位置
1. **实体配置类**:缺少`.HasColumnType("timestamp with time zone")`配置
2. **响应构建**:使用了`DateTime.UtcNow`而不是实体的时间字段
## 修复方案
### 1. 修复的实体配置类
#### Device相关
-`ProtocolVersionConfiguration`
-`CellularDeviceConfiguration`
#### Identity相关
-`AppRoleConfiguration`
-`AppUserConfiguration`
#### 其他
-`BaseEntityConfiguration`
-`PermissionConfiguration`
-`LoginLogConfiguration`
### 2. 修复的CommandHandler响应
#### ProtocolVersion相关
-`UpdateProtocolVersionCommandHandler`:使用`existingProtocolVersion.UpdatedAt`
#### Device相关
-`UpdateDeviceCommandHandler`:使用`existingDevice.UpdatedAt`
### 3. 修复内容
#### 实体配置类修复
```csharp
// 修复前
builder.Property(e => e.CreatedAt)
.IsRequired()
.HasComment("创建时间");
// 修复后
builder.Property(e => e.CreatedAt)
.IsRequired()
.HasColumnType("timestamp with time zone")
.HasComment("创建时间");
```
#### 响应构建修复
```csharp
// 修复前
UpdatedAt = DateTime.UtcNow
// 修复后
UpdatedAt = existingEntity.UpdatedAt
```
## 修复的字段类型
### 1. 时间戳字段
- `CreatedAt` / `CreatedTime`:创建时间
- `UpdatedAt` / `ModifiedTime`:更新时间
- `LastLoginTime`:最后登录时间
- `LoginTime`:登录时间
- `ReleaseDate`:发布日期
### 2. 数据库类型
- PostgreSQL: `timestamp with time zone`
- 确保所有DateTime字段都使用UTC时间
## 最佳实践
### 1. 时间处理原则
```csharp
// ✅ 正确:使用UTC时间
DateTime.UtcNow
// ❌ 错误:使用本地时间
DateTime.Now
// ❌ 错误:使用未指定Kind的时间
new DateTime(2024, 1, 1)
```
### 2. 实体配置
```csharp
// ✅ 正确:明确指定PostgreSQL时间戳类型
builder.Property(e => e.CreatedAt)
.HasColumnType("timestamp with time zone");
// ❌ 错误:依赖默认类型推断
builder.Property(e => e.CreatedAt);
```
### 3. 响应构建
```csharp
// ✅ 正确:使用实体的时间字段
response.UpdatedAt = entity.UpdatedAt;
// ❌ 错误:重新生成时间
response.UpdatedAt = DateTime.UtcNow;
```
## 数据库迁移
### 1. 现有数据库
如果数据库中已有数据,需要确保:
- 所有DateTime字段都存储为UTC时间
- 列类型为`timestamp with time zone`
### 2. 新数据库
- 实体配置会自动生成正确的列类型
- 所有时间字段都会使用UTC时间
## 验证方法
### 1. 代码验证
```csharp
// 检查DateTime.Kind
if (entity.CreatedAt.Kind != DateTimeKind.Utc)
{
throw new InvalidOperationException("DateTime must be UTC");
}
```
### 2. 数据库验证
```sql
-- 检查列类型
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;
```
## 总结
这次修复确保了:
1. **数据类型一致性**:所有DateTime字段都使用PostgreSQL的`timestamp with time zone`类型
2. **时间标准统一**:所有时间都使用UTC标准
3. **配置明确性**:实体配置中明确指定了数据库列类型
4. **响应准确性**:响应中使用实体的实际时间而不是重新生成的时间
这种修复方式为整个系统提供了统一的时间处理标准,确保了与PostgreSQL数据库的完全兼容性。