Skip to content
bitzorcas
中EN

Guide

种子数据导出

从批准的 legacy staging 提取 14 类基础数据,完成 owner 归属与业务键归一化,并安全评审写入的插入符分隔 CSV。

Last updated

BitzOrcas.SeedData.Exporter 是一次性/受控迁移工具:它从 legacy SQL Server staging 读取 14 类平台基础数据,修正旧表名和关系键,并把 CSV 分发给 Framework、MasterData、Authorization 与 Menu owner。它不是生产备份、通用 ETL,也不会替你判断数据是否可以进入源码仓库。

数据流与责任边界

是否

批准的 legacy staging

固定 SQL 查询与租户过滤

表名/拼写/业务键归一化

歧义或缺失引用?

抛错,停止导出

按 owner 写 CSV

git diff + PII/Secret 评审

Schema seed validation

空库 + 升级库幂等测试

导出器只负责技术转换。数据 owner 负责批准源环境、目标租户、数据最小化、CSV 内容和最终提交。

当前限制先读

当前实现没有 --dry-run、预览 manifest、临时 staging、原子目录替换或 --no-overwrite。它在启动后创建输出目录,并通过 File.Create(path) 直接截断/覆盖同名 CSV;中途失败可能留下“前几张已更新、后几张仍旧”的混合目录。

配置加载与安全来源

配置按 Configuration provider 后写覆盖前写的顺序加载:appsettings.json、appsettings.local.json、SEED_ 前缀环境变量、命令行。属性位于 Exporter section,环境变量因此使用 SEED_Exporter__SourceConnectionString 形态。

Terminal window
# 连接串只进入当前 shell;不要写入命令历史、CI 日志或已跟踪 JSON。
export SEED_Exporter__SourceConnectionString="$LEGACY_STAGING_CONNECTION"
export SEED_Exporter__TargetTenantId='1000001'
export SEED_Exporter__PlatformTenantId='0'
# 四个 owner 输出先全部重定向到独立临时目录。
export SEED_Exporter__OutputDirectory="$TMPDIR/bitz-seed/framework"
export SEED_Exporter__MasterDataOutputDirectory="$TMPDIR/bitz-seed/master-data"
export SEED_Exporter__AuthorizationOutputDirectory="$TMPDIR/bitz-seed/authorization"
export SEED_Exporter__MenuOutputDirectory="$TMPDIR/bitz-seed/menu"

程序会把日志中的 Password/Pwd 值替换为 ***,但这不保证异常堆栈、数据库驱动日志或 shell 历史都已脱敏。运行日志仍按敏感制品处理。

运行前检查

  1. 源库必须是批准的、已脱敏且版本明确的 staging snapshot,不直接连生产主库。
  2. 使用最小只读 SQL 登录,仅允许读取列出的 legacy 表。
  3. 明确 TargetTenantId;默认 1000001 只是配置样例,不是安全默认业务租户。
  4. PlatformTenantId 必须匹配旧系统的平台数据约定,通常是 0。
  5. 四个临时输出目录必须为空或其旧内容已有校验和备份。
  6. 记录源码 Commit、源快照标识、执行人、审批单与运行时间。
Terminal window
# 从仓库根目录构建 Release;先让编译和架构规则暴露工具漂移。
dotnet build src/Tooling/BitzOrcas.SeedData.Exporter \
--configuration Release
# 确认输出变量没有误指向受版本控制的正式 Assets。
env | rg '^SEED_Exporter__(Output|MasterDataOutput|AuthorizationOutput|MenuOutput)Directory='

执行导出

工具以当前工作目录解析相对配置路径。README 的默认值假设进入项目目录后运行;从仓库根执行时应使用绝对输出目录,避免相对路径落到意外位置。

Terminal window
# 在项目目录运行,保持 appsettings.local.json 与默认相对路径语义一致。
cd src/Tooling/BitzOrcas.SeedData.Exporter
dotnet run --configuration Release

启动时先执行 ValidateOptions,再创建四个目录、打开 SqlConnection,按固定顺序查询和写文件。日志显示连接串掩码、租户和每个 owner 的绝对目录;发现目录不对时立即取消并丢弃临时输出。

14 类导出与归一化

Legacy 来源输出文件Owner关键转换
SysTenant100-sys_platform_tenant.csvFramework 兼容Status bool→enum、Connection→ConnectionString
SysLanguage110-sys_language.csvMasterData平台租户、未删除
SysCountry120-sys_country.csvMasterData平台租户、未删除
SysIndustrySetting130-sys_industry_setting.csvMasterData平台租户、未删除
SysGeneralCodeGroups140-sys_general_code_group.csvMasterData旧复数表名归一化
SysGeneralCodes141-sys_general_code.csvMasterData表名与树字段兼容
SysGeneralCodeTexts142-sys_general_code_text.csvMasterData表名归一化
SysExchangeRates150-sys_exchange_rate.csvMasterData表名归一化
SysPubicHoliday160-sys_public_holiday.csvMasterData修正 legacy 拼写缺失的 l
SysRoleTypes200-sys_role_type.csvAuthorization表名归一化
SysRoles210-sys_role.csvAuthorization平台模板 + 目标租户覆盖,按角色名归一化
SysModules220-sys_module.csvMenuId/模块码建立稳定字典
SysPermission230-sys_permission.csvAuthorizationMid 归一化为模块码
SysRoleModulePermission240-sys_role_module_permission.csvAuthorizationId 关系改为角色名/模块码/权限码

源码 README 是这 14 类映射的权威维护说明。新增或移除类别时,应同步 exporter、owner seed step、资产清单、验证测试和本页源码事实门禁。

Fail-closed 关系处理

模块、权限、角色关系不能“尽量导出”。实现通过 AddStableKey 同时登记 legacy Id 与业务码:空 key 直接失败,同一个 key 指向两个不同值视为歧义并失败。权限缺少 code、引用未知 module,或用户独占关系无法归属角色时也必须停止。

目标租户角色会覆盖同名平台角色模板,最终投影到目标 TenantId。这是一项迁移规则,不是多租户运行时的通用合并语义;评审时必须检查覆盖数量和角色权限差异。

CSV 实际格式

输出不是逗号分隔,而是与当前 CsvSeedReader 一致的 ^ 分隔。CsvHelper 写 header,DateTime 格式限定为带毫秒、不带时区的 ISO 风格;写入使用当前 .NET Encoding.UTF8。文件名顺序与 seed Order 约定配合,但 Runner 最终以注册步骤的 Order 和 DependsOn 调度。

Terminal window
# 检查文件数量、分隔符和首行;内容可能敏感,不把完整行贴入公开日志。
find "$TMPDIR/bitz-seed" -type f -name '*.csv' -print | sort
head -n 1 "$TMPDIR/bitz-seed/authorization/230-sys_permission.csv"
# 拒绝意外逗号表头和空文件。
find "$TMPDIR/bitz-seed" -type f -name '*.csv' -size 0 -print
rg -n '^[^^]+,[^^]+' "$TMPDIR/bitz-seed" --glob '*.csv'

SysTenant 查不到目标租户时当前只打印 WARNING 并继续,不会令进程失败。这是一个必须由运行后清单补偿的现状:确认 100-sys_platform_tenant.csv 是否存在且来自本次执行。

与正式 owner Assets 比较

不要整目录复制。逐 owner 比较相对文件名、header、行数、稳定业务键和敏感字段,再选择性更新。

Terminal window
# 先看清单和统计,再看逐行 diff。
find "$TMPDIR/bitz-seed" -type f -name '*.csv' -exec wc -l {} + | sort
# 示例:只比较权限资产;路径按当前仓库 owner 目录核对。
git diff --no-index \
src/Platform/Authorization/BitzOrcas.Platform.Authorization.Infrastructure/Seeders/Assets/230-sys_permission.csv \
"$TMPDIR/bitz-seed/authorization/230-sys_permission.csv" || true

重点检查新增/删除权限、角色覆盖、模块码变化、租户 ID、审计人、连接字符串、邮箱/电话、固定 token 和演示凭据。任何无法解释的批量变化都应回到 source snapshot 和查询规则定位。

Seed 验证与幂等

Terminal window
# 对最终候选 owner Assets 做值长度/格式验证,不需要数据库连接串。
dotnet run --project src/Tooling/BitzOrcas.SchemaMaintenance -- \
--validate-seed
# 验证 Seed 相关架构规则和真实集成合同。
dotnet test tests/BitzOrcas.Architecture.Tests \
--configuration Release \
--filter 'FullyQualifiedName~Seed'
dotnet test tests/BitzOrcas.Integration.Tests \
--configuration Release \
--filter 'Category=Docker&FullyQualifiedName~Seed'

在空库验证首次插入,在已有库验证 replay:行数不膨胀、owner 管理字段收敛、运行时字段不被覆盖、依赖顺序正确。只验证“第二次不抛异常”不够。

失败恢复

当前写入不是原子事务。任意异常后都应把整个临时根目录标记为失败并删除,修复源数据或配置后从空目录重跑;不要只重跑缺失的后半部分,再把不同 run 的文件拼接为一个候选集。

数据库读取取消或网络中断同样按失败处理。保留掩码日志、首个异常、已写文件清单和源 snapshot ID用于定位,但不要保留含真实 secret/PII 的共享附件。

交付清单

  • 源 staging、快照、只读账号和数据审批可追溯;
  • 四个输出目录均为临时目录,没有直接覆盖正式 Assets;
  • 14 个预期文件的存在性、header、行数与 owner 已核对;
  • 未知 module、空 permission、歧义 role/key 均 fail-closed;
  • 目标租户 seed 未因 WARNING 悄然缺失;
  • PII、Secret、连接串、演示凭据扫描通过;
  • Schema validation、空库和升级库幂等合同通过;
  • 只选择性提交可解释 diff,并记录生成来源与证据。

另见

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%