# 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` 即可（`EnsurePlatformDatabaseAsync` → `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#数据库启动流程)**

摘要：`EnsurePlatformDatabaseAsync` → `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` + 原始字符串比较可能触发转换异常；旧值刷库需绕过 converter（参见 `LegacyStatusNormalizationMigrator`）。

---

## 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
