Numbering 把规则定义、段定义和分配事实分开持久化。三者通过字符串键连接,没有数据库外键或统一聚合事务。
1. 所有权结构
规则和设置是配置目录;GenerateRecord 是运行事实,绝不由 seed 管理。
2. Rule 索引
Rule 表只有非唯一索引 Tenant + TableName + Field + IsActive + Priority。数据库不阻止同租户重复 Table/Field/RuleName,也不保证唯一默认规则或 Priority。
seed matcher 使用 TableName + Field + RuleName,但这只是导入语义,不是数据库唯一约束。
3. Setting 索引
Setting 索引是 RuleId + Sort,未标 unique,且索引列没有显式 TenantId。表本身仍是 tenant/soft-delete,但数据库可存在同规则同 Sort 多行。
Generator 加载后按 Sort 排序;相同 Sort 的次序未定义。
4. GenerateRecord 索引
唯一索引:Tenant + TableName + Field + SequenceNumberStr。另一个普通索引:Tenant + TableName + Field + Prefix。
没有 Prefix+SequenceNumber 唯一索引,也没有规则版本、幂等请求键或业务聚合 Id。
5. 编译期元数据
// ① Generator 在编译期收集租户、软删与索引元数据。[BitzTable("SysSequenceNumberGenerateRecord", IsTenant = true, IsSoftDelete = true)][BitzIndex( "UX_SysSequenceNumberRecord_Tenant_Table_Field_SeqStr", "TenantId", "TableName", "Field", "SequenceNumberStr", IsUnique = true)]public sealed class SysSequenceNumberGenerateRecord : BizEntityBase{ // ② 完整串是数据库最终唯一防线。 [BitzColumn(Length = 128, IsRequired = true)] public string SequenceNumberStr { get; set; } = string.Empty;}Infrastructure 只依赖 IEntitySet<T>,不引用 SqlSugar/EF Core adapter。
6. Seed 编排
| Step | Order | SeedId | 自然键 |
|---|---|---|---|
| Rule | 700 | sys_sequence_number_rule | TableName + Field + RuleName |
| Setting | 710 | sys_sequence_number_rule_setting | RuleId + Sort |
Setting 显式 DependsOn Rule。两者基于 EntitySetCsvSeedStepBase<T> 逐行 upsert。
7. 当前资产
规则 CSV 是表头加两行,设置 CSV 是表头加六行。所有行 TenantId=1000001,IsInternal=true、IsEnabled=true、IsDeleted=false。
资产的 RuleId 分别是 DemoCase-SerialId-demo_case_serial 和 DemoInvoice-SerialId-demo_invoice_serial,与运行时拼接一致。
8. Seed 更新边界
Rule Copy 更新 separator、补偿、活跃、条件、优先级、ConditionScope、说明以及基础租户/组织/状态字段。它不修改 TableName、Field、RuleName。
Setting Copy 更新所有段配置和基础字段,但不修改 RuleId、Sort。更改自然键会被视为新行,旧行不会自动删除。
9. CSV 严格性
共享 CsvSeedReader 关闭 HeaderValidated/MissingFieldFound 严格回调,关键列可疑时主要告警。Numbering 没有额外规则 DSL lint。
因此 seed 成功不证明条件 JSON、段类型、日期格式、映射 JSON、唯一 Sort 或字符串最大长度有效。
10. 宿主组合
API Host 显式调用 AddBitzOrcasNumberingPlatform,注册:
// ① 三个 IEntitySet<T> 由选择的 ORM generated adapter 提供。services.AddBitzOrcasGeneratedPersistenceAdapters(persistenceProvider);
// ② Numbering 只提供 Framework Port 的 scoped 实现。services.AddBitzOrcasNumberingPlatform();
// ③ 两个 seed step 由生成 manifest 参与统一 seed 编排。services.AddBitzOrcasGeneratedSeedSteps();没有 Numbering endpoint mapping。
11. Feature 真相
治理目录有一个默认启用的 numbering.sequence Feature。但 GenerateAsync 不注入 Feature evaluator,模块也没有 Endpoint/Handler 执行 Feature gate。
Feature 被收录不等于运行时生成已按租户套餐关闭。调用业务必须自己执行,或未来在 Port decorator 中统一强制。
12. 没有 Permission/管理面
模块没有 PermissionCatalog、规则 CRUD、发布、预览、版本、审批或审计。生产修改只能通过 seed/数据库运维路径,风险较高。
任何管理 API 都应属于 Numbering Application/Contracts,而不是把 IEntitySet 暴露给宿主。
13. 业务 owner 集成
业务模块依赖 Framework 的 ISequenceNumberGenerator,传稳定 TableName/Field 与显式 EntityValues;不依赖 Numbering Infrastructure 的 record 类型。
// ① 快照只包含规则/分段真正需要的字段。var values = new Dictionary<string, object?>{ ["OfficeId"] = invoice.OfficeId, ["InvoiceType"] = invoice.TypeCode};
// ② 可选回调由 Invoice owner 实现,不把 IQueryable 暴露给 Numbering。var request = new SequenceNumberRequest( "Invoice", "SerialId", values, BusinessSerialContext: invoiceSerialContext);
// ③ 分配后立即把字符串固化为聚合事实。var serial = await generator.GenerateAsync(request, cancellationToken);14. 当前消费缺口
源码全局搜索未发现业务 Command 构造 SequenceNumberRequest;注册和测试存在,但真实业务主路径尚无证据。GA 前必须建立至少一个生产 tracer-bullet 消费者。
15. 核查命令
# 三张表、索引和两个 seed step。rg -n "BitzTable|BitzIndex|SeedId|WhereColumns|DependsOn" src/Platform/Numbering -g '*.cs'
# 生产消费证据。rg -n "new SequenceNumberRequest|ISequenceNumberGenerator" src -g '*.cs' --glob '!**/bin/**' --glob '!**/obj/**'