Skip to content
bitzorcas
中EN

Reference

Numbering 持久化、种子与业务集成

三张租户行的索引语义、编译期元数据、两步 CSV seed、宿主组合、Feature 边界和业务 owner 的正确接入方式。

Last updated

Numbering 把规则定义、段定义和分配事实分开持久化。三者通过字符串键连接,没有数据库外键或统一聚合事务。

1. 所有权结构

computed RuleId

SysSequenceNumberRule
Table + Field + RuleName

SysSequenceNumberRuleSetting
RuleId + Sort

NumberingSequenceNumberStore

SysSequenceNumberGenerateRecord
Prefix + Number + FullString

规则和设置是配置目录;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. 编译期元数据

owner-local 计数事实形状
// ① 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 编排

StepOrderSeedId自然键
Rule700sys_sequence_number_ruleTableName + Field + RuleName
Setting710sys_sequence_number_rule_settingRuleId + 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 类型。

业务 Handler 的集成边界
// ① 快照只包含规则/分段真正需要的字段。
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. 核查命令

Terminal window
# 三张表、索引和两个 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/**'

模块总览 · 规则与分段

100%

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