MySqlSchemaInspector Query Builder / Row Mapper 設計
1. 文件目的
本文件整理 MySqlSchemaInspector 第一版的純程式設計,聚焦在 query builder、row mapper、snapshot assembly、錯誤處理與單元測試。
此設計仍不導入 MySqlConnector、不修改 .csproj、不建立真實 connection string、不連線 MySQL、不讀取真實 information_schema,也不執行任何 DDL。
2. 設計結論
第一版建議先把真實 MySQL Inspector 拆成三個可單獨測試的區塊:
| 區塊 | 職責 | 是否需要真實 DB |
|---|---|---|
| Query Builder | 產生 information_schema 查詢與參數名稱 | 否 |
| Row Mapper | 將 table / column / index metadata row 轉成中間模型 | 否 |
| Snapshot Assembler | 將中間模型組成 schema snapshot | 否 |
這樣可以先驗證 MySQL 5.6.2 metadata 規則與 mapping 邏輯,等設計穩定後再確認是否導入 MySqlConnector。
3. 建議元件切分
| 元件 | 建議名稱 | 職責 |
|---|---|---|
| query builder | MySqlSchemaInspectorQueryBuilder | 產生 tables / columns / indexes 查詢 |
| metadata row | MySqlTableMetadataRow / MySqlColumnMetadataRow / MySqlIndexMetadataRow | 表示從 information_schema 讀出的原始欄位 |
| row mapper | MySqlSchemaMetadataMapper | 將 metadata row 轉成 schema model 所需資訊 |
| snapshot assembler | MySqlSchemaSnapshotAssembler | 依 table name 合併 table / column / index |
| inspector | MySqlSchemaInspector | 後續負責協調連線、查詢、mapping 與 result |
若實作時覺得元件過多,第一版可以先合併 mapper 與 assembler,但 query builder 建議保留獨立,方便測試參數化查詢。
4. Query Builder 設計
4.1 共通原則
每個 query 都必須符合:
- 使用
@DatabaseName參數,不直接拼接 database name。 - 必須限制
TABLE_SCHEMA = @DatabaseName。 - 可接受 table filter,但 table filter 也必須參數化。
- 必須有穩定排序,讓測試與人工驗證輸出一致。
- 不產生任何 DDL。
4.2 Table Query
用途:讀取指定 database 內的 table 清單。
建議欄位:
| 欄位 | 對應 |
|---|---|
TABLE_NAME | table name |
TABLE_COMMENT | table description |
ENGINE | table engine |
TABLE_COLLATION | table collation |
建議排序:
ORDER BY TABLE_NAME4.3 Column Query
用途:讀取 table 欄位 metadata。
建議欄位:
| 欄位 | 對應 |
|---|---|
TABLE_NAME | 所屬 table |
COLUMN_NAME | 欄位名稱 |
COLUMN_TYPE | 完整型別,例如 varchar(64) |
DATA_TYPE | 基礎型別,例如 varchar |
CHARACTER_MAXIMUM_LENGTH | 字串長度 |
NUMERIC_PRECISION | 數值精度 |
NUMERIC_SCALE | 小數位數 |
IS_NULLABLE | nullable |
COLUMN_DEFAULT | default value |
COLUMN_COMMENT | 欄位描述 |
ORDINAL_POSITION | 欄位順序 |
建議排序:
ORDER BY TABLE_NAME, ORDINAL_POSITION4.4 Index Query
用途:讀取 index 與 primary key metadata。
建議欄位:
| 欄位 | 對應 |
|---|---|
TABLE_NAME | 所屬 table |
INDEX_NAME | index name |
COLUMN_NAME | index 欄位 |
NON_UNIQUE | unique 判斷 |
SEQ_IN_INDEX | 複合 index 欄位順序 |
建議排序:
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEXINDEX_NAME = 'PRIMARY' 時應轉成 primary key metadata,不應當成一般 index。
5. Table Filter 設計
第一版支援兩種模式即可:
| 模式 | 行為 |
|---|---|
| 無指定 table | 讀取 database 內全部 table metadata |
| 指定 table names | 加入 TABLE_NAME IN (...) 條件 |
注意事項:
IN條件需產生@TableName0、@TableName1等參數。- 空陣列不應產生
IN (),應視為未指定 table filter 或回傳驗證錯誤。 - table name 不能直接串到 SQL 字串。
6. Row Mapper 設計
6.1 Table Row
| 輸入 | Mapping |
|---|---|
TABLE_NAME | required |
TABLE_COMMENT | null 時轉空字串 |
ENGINE | 保留 metadata,可作 warning 判斷 |
TABLE_COLLATION | 保留 metadata,可作 warning 判斷 |
若缺少 TABLE_NAME,應回傳標準錯誤。
6.2 Column Row
| 輸入 | Mapping |
|---|---|
COLUMN_NAME | required |
COLUMN_TYPE | 作為第一版型別比對主要來源 |
DATA_TYPE | 作為基礎型別與 warning 判斷 |
IS_NULLABLE | YES 轉 true,NO 轉 false |
COLUMN_DEFAULT | 保留原始值 |
COLUMN_COMMENT | null 時轉空字串 |
ORDINAL_POSITION | 用於排序 |
型別比對第一版建議保留完整 COLUMN_TYPE,不要過度正規化,避免 MySQL 5.6.2 的細節被吃掉。
6.3 Index Row
| 輸入 | Mapping |
|---|---|
INDEX_NAME | required |
COLUMN_NAME | required |
NON_UNIQUE | 0 轉 unique,1 轉 non-unique |
SEQ_IN_INDEX | 欄位順序 |
同一個 TABLE_NAME + INDEX_NAME 的多筆 row 應合併成同一個 index,欄位依 SEQ_IN_INDEX 排序。
7. Snapshot Assembly 設計
組裝順序建議:
- 先以 table rows 建立 table dictionary。
- 將 column rows 依
TABLE_NAME加入對應 table。 - 將 index rows 依
TABLE_NAME + INDEX_NAME分組。 PRIMARYindex 轉成 primary key metadata。- 一般 index 加入 table indexes。
- 若 column / index 指到不存在的 table,產生 warning 或 error。
第一版建議:
- table row 缺失但 column row 存在:回傳 warning,並建立 minimal table snapshot。
- index 指到不存在欄位:回傳 warning,不直接失敗。
- 欄位型別未知:回傳 manual review warning,不直接套用。
8. Result 與錯誤格式
建議 query builder / mapper / assembler 各自保留可測試的結果:
| 元件 | 成功輸出 | 失敗輸出 |
|---|---|---|
| Query Builder | SQL + parameter names | validation error |
| Row Mapper | metadata row model | missing required field error |
| Snapshot Assembler | schema snapshot + warnings | assembly error |
錯誤資訊至少包含:
ErrorCodeMessageSourceTableNameColumnNameIndexNameCorrelationId
9. 單元測試設計
第一批測試不依賴真實 DB,建議包含:
| 測試 | 預期 |
|---|---|
Table query 必含 TABLE_SCHEMA = @DatabaseName | 避免讀到其他 database |
Column query 依 TABLE_NAME, ORDINAL_POSITION 排序 | 輸出穩定 |
Index query 依 TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX 排序 | 複合 index 順序穩定 |
table filter 產生參數化 IN 條件 | 不直接拼接 table name |
空 table filter 不產生 IN () | 避免 SQL 錯誤 |
| nullable mapping | YES / NO 正確轉換 |
| unique mapping | NON_UNIQUE 正確轉換 |
| primary key mapping | PRIMARY 不當成一般 index |
| 複合 index assembly | 欄位順序正確 |
| 缺少 required metadata | 回傳標準錯誤 |
| 不存在 table 的 column / index | 回傳 warning |
10. 實作前停止線
以下仍需先確認,不得在本設計自動執行:
| 事項 | 原因 |
|---|---|
導入 MySqlConnector | 新增套件 |
修改 .csproj | 影響 restore / build |
| 實作真實 DB connection | 外部服務與密碼管理 |
讀取真實 information_schema | 真實 DB metadata 存取 |
| 修改 public method 簽章 | 可能破壞既有契約 |
| 改 ConsoleHost 啟動參數 | 影響使用流程 |
| 執行任何 DDL | 會修改資料庫 |
11. 建議下一步
若使用者尚未確認導入 MySqlConnector,下一步建議先做「Query Builder / Row Mapper 實作前確認」,把要新增的 class、method、測試檔與不改 public contract 的方式列清楚。
若使用者確認可導入 MySqlConnector,再進入 MySqlConnector 套件導入與真實 Inspector 第一版實作。