# MiGu.DB Migrations 使用手册 面向日常改表、发版与排错。当前默认 Provider 为 **Sqlite**,迁移目录为 `Migrations/Sqlite/`。 --- ## 1. 概念速览 | 概念 | 说明 | |------|------| | Migration | 一次 Schema 变更(建表/加列/索引等),对应一对 `*_Name.cs` + `*_Name.Designer.cs` | | ModelSnapshot | `MiGuDbContextModelSnapshot.cs`,当前模型总快照;下次 `add` 时与代码模型做 diff | | `__EFMigrationsHistory` | 数据库内表,记录已应用的 Migration Id | | DataMigrator | **数据**修补(刷旧状态、回填列),不是 Schema;启动时在 Migrate 之后执行 | **原则:Schema 只走 Migrations;业务代码禁止手写 CREATE/ALTER。** 三个文件职责: - `YYYYMMDDHHMMSS_Name.cs` → `Up()`/`Down()`,真正改库 - `YYYYMMDDHHMMSS_Name.Designer.cs` → 该次迁移的目标模型元数据(勿手改) - `MiGuDbContextModelSnapshot.cs` → 全库最新快照(勿手改,除非处理合并冲突) --- ## 2. 环境准备 ### 2.1 工具 仓库根目录(`Migu2.0`)执行: ```powershell # 全局工具(任选) dotnet tool install --global dotnet-ef --version 8.0.10 # 或本地工具目录(本仓库曾用此方式) dotnet tool install dotnet-ef --version 8.0.10 --tool-path .\.tools .\.tools\dotnet-ef --version ``` 版本需与项目 EF Core **8.0.x** 对齐。 ### 2.2 工程关系 | 参数 | 值 | |------|-----| | 迁移所在工程 | `MiGu.DB` | | 启动工程 | `MiGu.Server`(提供配置与 Design 包) | | DbContext | `MiGu.DB.Kernel.Context.MiGuDbContext` | | Design-time 工厂 | `MiGu.DB.Kernel.Design.MiGuDbContextFactory` | `MiGu.Server.csproj` 已引用 `Microsoft.EntityFrameworkCore.Design`;`MiGu.DB` 含 Sqlite 等 Provider 包。 --- ## 3. 生成 Migration(日常流程) ### 3.1 改模型 在 `MiGu.DB/Domains` 改实体或 `IEntityTypeConfiguration`,保存后编译通过: ```powershell dotnet build .\MiGu.DB\MiGu.DB.csproj ``` ### 3.2 添加迁移 在**解决方案根目录**执行(PowerShell): ```powershell dotnet ef migrations add <迁移名称> ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --output-dir Migrations/Sqlite ` --namespace MiGu.DB.Migrations.Sqlite ` --context MiGuDbContext ``` 命名建议(PascalCase,无空格): | 场景 | 示例名 | |------|--------| | 首库 | `InitialPlatform`(已存在,勿重复) | | 加表 | `AddWmsXxxTable` | | 加列 | `AddStoragePriorityColumn` | | 加索引 | `AddStockEventOperatedAtIndex` | ### 3.3 生成后检查(必做) 1. 新文件应在:`MiGu.DB/Migrations/Sqlite/` 2. 打开 `*_Name.cs`,确认 `Up()` 只包含**本次预期**变更(无误删表、无多余重建) 3. 确认 `MiGuDbContextModelSnapshot.cs` 仍在 `Migrations/Sqlite/` - 若出现在 `MiGu.DB/MiGu/DB/Migrations/Sqlite/` 等错误路径:把 Snapshot **移回**正确目录并删掉空目录(`--namespace` 偶发路径问题) ### 3.4 应用到本地库 启动 `MiGu.Server` 即可(`Program.cs` 直接调用 `MigrateMiGuDbAsync`),或: ```powershell dotnet ef database update ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext ``` --- ## 4. 常用命令 ```powershell # 列出迁移 dotnet ef migrations list ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext # 生成 SQL 脚本(发版/DBA 审阅,不直接连库执行也可) dotnet ef migrations script ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext ` --output .\MiGu.DB\Migrations\Sqlite\script.sql # 从某迁移到最新(含幂等脚本时加 --idempotent) dotnet ef migrations script FromMigration ToMigration ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext ` --idempotent # 删除「尚未应用到任何重要库」的最后一次迁移(仅开发) dotnet ef migrations remove ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext # 回滚到指定迁移(会执行 Down,生产慎用) dotnet ef database update <目标迁移名> ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --context MiGuDbContext ``` 使用本地工具时,将 `dotnet ef` 换成 `.\.tools\dotnet-ef`。 --- ## 5. 启动时发生了什么 **完整说明(顺序、配置、SchemaMode、开发注意)见:** → **[MiGu.Server/README.md · 数据库启动流程](../MiGu.Server/README.md#数据库启动流程)** 摘要:`MigrateMiGuDbAsync`;`Database:SchemaMode` 为 `EnsureCreated` 或 `Migrate`;之后按需跑 `IDataMigrator`。 **Migrate 基线:** 已有表、无 History 时,会把**全部** pending Migration 写入 `__EFMigrationsHistory`(假定 EnsureCreated 库已对齐模型 tip)。发版前若开发期改过模型,须先 `migrations add` 再切 `Migrate`。 --- ## 6. Schema 变更 vs 数据修补 | 需求 | 做法 | |------|------| | 新表/新列/索引/改列类型 | `migrations add` → 提交迁移文件 | | 刷旧枚举字符串、回填列 | 新增 `IDataMigrator`,注册到 `AddMiGuDataMigrators` | | 开发机整库清空重来 | 删 `data/platform.db*` 后启动(等同空库 Migrate);**不要**在生产用 EnsureDeleted | 注意:带 `HasConversion` 的枚举列,用 `ExecuteUpdate` + 原始字符串比较可能触发转换异常;空 LayoutMode 等特例用 raw UPDATE(参见 `AreaLayoutModeDefaultMigrator`)。 --- ## 7. 协作与发版 1. **迁移文件必须入库**(含 Designer、Snapshot) 2. 多人同时改模型易冲突 Snapshot:保留一方迁移,另一方 `remove` 后基于最新代码重新 `add` 3. 已合并到主分支并可能已应用到共享库的迁移:**不要** `migrations remove` 或改写历史 `Up()` 4. 发版包随程序集带上 Migration;现场首次升级靠启动 Migrate(或预执行 `migrations script`) --- ## 8. 其他 Provider(预留) `IDbProviderSetup` 已预留 MySql / Npgsql / SqlServer。首轮只有 Sqlite 迁移套。 将来为企业库生成独立套时: ```powershell # 示例:输出到 Migrations/MySql,namespace 同步修改 dotnet ef migrations add InitialPlatform ` --project .\MiGu.DB\MiGu.DB.csproj ` --startup-project .\MiGu.Server\MiGu.Server.csproj ` --output-dir Migrations/MySql ` --namespace MiGu.DB.Migrations.MySql ` --context MiGuDbContext ``` 并确保对应 Provider 的 `MigrationsAssembly` / 运行时能发现该套迁移(按需拆程序集或过滤命名空间)。 --- ## 9. 常见问题 | 现象 | 处理 | |------|------| | `dotnet ef` 找不到 | 安装 8.0.10 工具,或用 `.\.tools\dotnet-ef` | | Design-time 连错库 | 检查 `MiGuDbContextFactory`(默认 `platform.db`);运行时以 Server 配置为准 | | Snapshot 生成到奇怪目录 | 移回 `Migrations/Sqlite/` | | 旧库启动重复建表失败 | 确认基线逻辑是否写入 History;备份后必要时手工插入 Initial 行 | | 改完实体 `add` 生成空迁移 | 模型无差异或未编译;先 `dotnet build` | | 想撤销未提交的迁移 | `migrations remove`(确认未被他人/现场应用) | --- ## 10. 检查清单(每次提 PR) - [ ] `dotnet build` 通过 - [ ] 新迁移仅含预期 DDL - [ ] 文件在 `Migrations/Sqlite/`,Snapshot 路径正确 - [ ] 本地启动一次,确认 Migrate 成功 - [ ] 若有数据刷库,已加幂等 `IDataMigrator` 并注明 Order - [ ] 未改写已发布的历史 Migration