# 数据模型与迁移约束(Hua.Todo 专属) > 适用范围:本规则属于 **项目规则**(仅 Hua.Todo 项目生效)。 > > 描述当前数据库实体、字段约束、EF Core 迁移历史,约束智能体在改 schema 时遵循的纪律。 ## 一、技术栈 - ORM:**EF Core** - 数据库:**SQLite**(嵌入式与 Host 开发都走 SQLite;生产 Host 可切其他后端) - DbContext:[TodoDbContext](file:///d:/Proj/6.Hua.Todo/src/Hua.Todo.Application/Data/TodoDbContext.cs) - 迁移目录:`Hua.Todo.Application/Migrations/` - **表名规范**:遵循 ABP 模板规范,格式为 `T_{实体名}s`,如 `T_Tasks`、`T_Users` ## 二、当前实体清单(src/Hua.Todo.Core/Entities/) ### 2.1 TaskEntity(待重构为 ABP 基类) > ⚠️ **重大变更预警**:TaskEntity 计划继承 `FullAuditedEntityWithUser`,重构后将包含 ABP 全部审计字段。此改为破坏性变更,详见 [09-CloudSync-同步策略改进方案.md](../../../docs/project/研发工单-v1.2.0/09-CloudSync-同步策略改进方案.md)。 **重构前(当前)**: | 字段 | 类型 | 说明 | |---|---|---| | `Id` | `int` | 主键(待改为 Guid) | | `UserId` | `Guid` | 任务所属用户 | | `Title` | `string` | 标题 | | `Priority` | `TaskPriority` | 优先级枚举 | | `IsCompleted` | `bool` | 是否完成 | | `CreatedAt` | `DateTime` | 创建时间 | | `UpdatedAt` | `DateTime` | 更新时间 | | `ParentTaskId` | `int?` | 父任务ID(待改为 Guid?) | **重构后(ABP 标准)**: 继承 `FullAuditedEntityWithUser` 后自动获得: | ABP 审计字段 | 类型 | 说明 | |---|---|---| | `Id` | `Guid` | 主键(强制 Guid) | | `ExtraProperties` | `ExtraPropertyDictionary` | 扩展属性(基类提供) | | `ConcurrencyStamp` | `string?` | 并发戳 | | `CreationTime` | `DateTime` | 创建时间 | | `CreatorId` | `Guid?` | 创建人 | | `LastModificationTime` | `DateTime?` | 最后修改时间 | | `LastModifierId` | `Guid?` | 最后修改人 | | `IsDeleted` | `bool` | 软删除标记 | | `DeletionTime` | `DateTime?` | 删除时间 | | `DeleterId` | `Guid?` | 删除人 | 业务字段保留:`UserId`、`Title`、`Priority`、`IsCompleted`、`ParentTaskId` ### 2.2 其他实体 | 实体 | 关键字段 | 约束 | |---|---|---| | `TaskPriority` | 枚举 | Priority 字段对应类型 | | `UserEntity` | `Id`、`UserName`、`PasswordHash`、`PasswordSalt`、`Role`、`MustChangePassword` | 唯一索引:`UserName` | | `UserSessionEntity` | `SessionId`、`UserId`、`ExpiresAtUtc`、`IsStepUp`、`StepUpExpiresAtUtc` | session token 由 DB 管理(非纯 JWT) | | `SecurityPolicyEntity` | `UserId`、`AllowPersist`、`AllowSync`、`SecondFactorExpiryMinutes`、`IsTrustedDeviceOnly` | 与 User 一对一 | | `AuditLogEntity` | `Id`、`UserId`、`Action`、`OccurredAtUtc`、`Details` | 关键安全事件 | | `TodoUserIds` | `LocalUserId = "local"` | 静态常量类,非实体 | ## 三、迁移历史(按时间) | 迁移 | 含义 | |---|---| | `20260313044926_InitialCreate` | 初始 Tasks 表 | | `20260313092658_AddParentTaskId` | 父子任务字段 | | `20260406172936_AddCloudSyncCoreEntities` | Users / UserSessions / SecurityPolicies | | `20260406173734_AddAllowSyncToSecurityPolicy` | `AllowSync` 字段 | | `20260413140347_UpdateSecurityEntities` | 安全实体调整 | | `20260413140753_AddAuditLogs` | AuditLogs 表 | | `20260424164713_AddPasswordSaltToUsers` | 密码加盐 | | `20260510171230_AddMustChangePasswordToUsers` | 强制改密标志 | | `MakeTaskEntityAbpCompatible`(待创建) | 重构为继承 ABP 基类,新增审计字段,主键从 `int` 改为 `Guid` | ## 四、改 schema 必须遵守的纪律 1. **禁止手改 `*ModelSnapshot.cs`**:使用 `dotnet ef migrations add` 命令生成 2. **迁移命名以动词开头**:`AddXxx` / `UpdateXxx` / `RemoveXxx` / `RenameXxx` 3. **避免破坏性迁移**:删除字段前先确认数据已被业务层迁移;优先采用"双写/兼容期" 4. **嵌入式宿主启动时自动 Migrate**:见 `EmbeddedWebServerService.cs` 中的 `db.Database.Migrate()` 调用;任何破坏迁移幂等性的改动都会让客户端启动失败 5. **业务字段命名沿用 `Task*` 词根**(即业务实体),编码工作侧不要在实体上用 `Task` 词根之外的同义词 6. **`UserId` 字段不可为空**:本地模式使用 `TodoUserIds.LocalUserId = "local"`,云端模式使用真实用户 GUID 字符串 ## 五、DTO 与实体的映射边界 - **实体(Entity)**:仅在 `Hua.Todo.Core` / `Hua.Todo.Application/Data` 内部使用 - **DTO(Models)**:跨进程边界(HTTP API、WebView 注入)使用,位于 `Hua.Todo.Application/CloudSync/Models/` 与 `Hua.Todo.Application/Models/` - **不要把实体直接序列化为 API 响应**:避免暴露内部字段、避免循环引用 ## 六、检查清单(schema 变更) 1. [ ] 是否新增了 EF Core 迁移(而非手改快照)? 2. [ ] 迁移名称是否以 `AddXxx`/`UpdateXxx`/`RemoveXxx` 开头? 3. [ ] 是否在 [docs/manual/07-技术架构设计.md](../../../docs/manual/07-技术架构设计.md) 中同步更新数据模型描述? 4. [ ] 是否在 [docs/manual/03-版本记录.md](../../../docs/manual/03-版本记录.md) 中追加非琐碎变更条目? 5. [ ] 是否在嵌入式宿主上验证了启动时 Migrate 不报错?