在企业级多租户软件中,新环境交付、自动化 CI 测试以及日常本地开发均高度依赖数据库初始数据:平台内置语言币种、RBAC 系统角色与权限、示范律所与样本案件卷宗必须能够可靠、幂等地注入数据库。 传统的手工 SQL 脚本存在致命缺陷:反复执行时频发主键冲突(PK Violation)、无法表达模块间的数据依赖拓扑,更难以根据当前环境(生产环境 vs. 演示环境)进行精准的防污染阻断。
BitzOrcas.Modern 确立了基于 ISeedStep 与 ISeedRunner 的声明式分层种子体系:
- 统一步骤契约(
ISeedStep):每个模块独立声明自身的种子步骤,包括全局唯一SeedId、执行优先级Order、版本号Version与强依赖DependsOn; - 四维环境作用域门禁(
SeedScope):显式区隔Global(全局通用)、Tenant(租户基线)、Demo(演示体验)与ProductionSafe(生产安全增量),Demo级别数据在 Staging 和 Production 环境被 Runner 自动阻断; - DAG 依赖图拓扑排序:
ISeedRunner在启动时自动校验所有种子的前置依赖,确保外键父表数据先行就绪,杜绝隐式依赖导致的导入失败; - 一键架构初始化命令行:通过
dotnet run --project src/Hosts/BitzOrcas.Api -- --init-schema自动在表结构迁移完成后串联执行种子填充。
本指南以法律科技核心场景——在案件管理模块(BitzOrcas.Modules.Legal)中新增**“示范民商事案件卷宗种子步骤(LegalDemoMattersSeedStep)”**为例,演示完整的开发与注册过程。
种子数据分层拓扑与执行流程
第一步:编写模块级 ISeedStep 种子步骤
在业务模块的基础设施层实现 ISeedStep 接口。通过注入仓储或只读模型 Store 执行幂等写入,并指定 SeedScope.Demo 确保其仅在非生产环境中激活:
using System;using System.Threading;using System.Threading.Tasks;using BitzOrcas.Domain.Abstractions;using BitzOrcas.Domain.Results;using BitzOrcas.Infrastructure.Seeders;using BitzOrcas.Modules.Legal.Domain;using Microsoft.Extensions.Logging;
namespace BitzOrcas.Modules.Legal.Seeders;
/// <summary>/// 民商事案件示范卷宗种子数据步骤/// </summary>/// <remarks>/// <para>负责在本地开发与演练环境中幂等注入示范案件卷宗数据。</para>/// <para>依赖 <c>identity_roles</c> 种子,确保主办律师用户已先行就绪。</para>/// </remarks>public sealed class LegalDemoMattersSeedStep : ISeedStep{ private readonly ICommandRepository<MatterIntake, string> _repository; private readonly ILogger<LegalDemoMattersSeedStep> _logger;
/// <summary> /// 初始化示范案件种子步骤 /// </summary> /// <param name="repository">写侧命令仓储窄端口。</param> /// <param name="logger">结构化日志记录器。</param> public LegalDemoMattersSeedStep( ICommandRepository<MatterIntake, string> repository, ILogger<LegalDemoMattersSeedStep> logger) { _repository = repository; _logger = logger; }
/// <summary> /// 执行顺序:300+ 属于业务演示数据层,位于基础设施与权限角色之后 /// </summary> public int Order => 320;
/// <summary> /// 全局唯一种子标识符 (建议 snake_case) /// </summary> public string SeedId => "legal_demo_matters";
/// <summary> /// 声明作用域分类:Demo 级别在 Staging 与 Production 环境自动跳过 /// </summary> public SeedScope SeedScope => SeedScope.Demo;
/// <summary> /// 种子数据版本号:用于追踪变更 /// </summary> public int Version => 1;
/// <summary> /// 强依赖的种子标识符列表:必须在此步骤执行之前完成 /// </summary> public string[] DependsOn => new[] { "identity_platform_tenants", "identity_roles" };
/// <summary> /// 异步执行幂等播种 /// </summary> public async Task ExecuteAsync(string environment, CancellationToken cancellationToken) { const string targetMatterId = "MAT-DEMO-2026-0001";
// 1. 严格幂等防重检查:若目标示范案件已存在,直接跳过 var existing = await _repository.FindAsync(targetMatterId, cancellationToken); if (existing.IsSuccess) { _logger.LogInformation("[LegalDemoMattersSeedStep] 目标示范案件【{MatterId}】已存在,跳过播种。", targetMatterId); return; }
// 2. 构造示范聚合根并触发领域创建方法 var demoMatter = MatterIntake.Create( id: targetMatterId, tenantId: "tenant-alpha-lawfirm", matterCode: "CIV-2026-0081", title: "示范案例:上海华芯微电子商业秘密侵权纠纷", clientId: "CLI-DEMO-001", leadLawyerId: "USR-LAWYER-01", claimAmount: 12000000.00m);
if (demoMatter.IsFailure) { _logger.LogError("[LegalDemoMattersSeedStep] 构造示范案件失败: {Error}", demoMatter.Error.Message); return; }
// 3. 提交持久化 var saveResult = await _repository.SaveAsync(demoMatter.Value, cancellationToken); if (saveResult.IsSuccess) { _logger.LogInformation("[LegalDemoMattersSeedStep] 成功幂等播种示范案件: {MatterId}", targetMatterId); } else { _logger.LogError("[LegalDemoMattersSeedStep] 持久化示范案件失败: {Error}", saveResult.Error.Message); } }}第二步:在依赖注入容器中注册 SeedStep
在模块扩展或基础设施注册方法中,将该步骤注册为 ISeedStep:
using BitzOrcas.Infrastructure.Seeders;using BitzOrcas.Modules.Legal.Seeders;using Microsoft.Extensions.DependencyInjection;
namespace BitzOrcas.Modules.Legal;
public static class LegalModuleExtensions{ public static IServiceCollection AddLegalModuleSeeders(this IServiceCollection services) { // 注册当前模块的种子步骤,由 ISeedRunner 自动扫描并参与拓扑排序 services.AddSingleton<ISeedStep, LegalDemoMattersSeedStep>(); return services; }}第三步:执行数据库架构初始化与种子数据注入
在终端中通过 API Host 提供的命令行入口执行建库与播种:
# 1. 生产环境安全模式:自动初始化数据表结构,仅播种 Global、Tenant 与 ProductionSafe 种子dotnet run --project src/Hosts/BitzOrcas.Api -- --init-schema
# 2. 仅校验或跳过种子播种 (用于只更新表结构)dotnet run --project src/Hosts/BitzOrcas.Api -- --init-schema --no-seed
# 3. 开发环境重置并强制重新播种演示密码USER__ADMIN__PASSWORD="YourStrongPassword123!" dotnet run --project src/Hosts/BitzOrcas.Api -- --init-schema --reset-demo-passwords总结
基于 ISeedStep 的声明式种子体系具备高度工程自洽性:
- 绝对幂等:实现层通过主键预检或
EntitySetCsvSeedStepBase差量合并,多次执行绝不抛出主键冲突; - 生产绝对防污染:
SeedScope.Demo受到 Runner 硬编码环境门禁控制,生产部署时自动阻断任何演示数据; - 拓扑依赖安全:
DependsOn机制在启动期形成校验闭环,杜绝因模块加载顺序错乱而导致的外键约束崩溃。