Skip to content
bitzorcas
中EN

Reference

Numbering Persistence, Seeding, and Business Integration

Three tenant-row index semantics, compile-time metadata, two-step CSV seeding, host composition, Feature boundaries, and correct owner integration.

Last updated

Numbering stores rule definitions, segment definitions, and allocation facts separately. String keys connect them; there is no database foreign key or aggregate transaction among the three.

1. Ownership shape

computed RuleId

SysSequenceNumberRule
Table + Field + RuleName

SysSequenceNumberRuleSetting
RuleId + Sort

NumberingSequenceNumberStore

SysSequenceNumberGenerateRecord
Prefix + Number + FullString

Rules and settings are configuration catalogs. GenerateRecord is runtime fact data and is never seed-managed.

2. Rule index

Rule has a non-unique Tenant + TableName + Field + IsActive + Priority index. The database does not prevent duplicate Table/Field/RuleName, multiple defaults, or duplicate priorities.

The seeder matches TableName + Field + RuleName, but an import natural key is not a unique database constraint.

3. Setting index

Setting indexes RuleId + Sort without uniqueness or explicit TenantId columns. The table still has tenant/soft-delete metadata, but duplicate Sort rows can exist under one rule.

The generator orders by Sort; equal values have undefined order.

4. GenerateRecord indexes

Unique: Tenant + TableName + Field + SequenceNumberStr. Normal: Tenant + TableName + Field + Prefix.

There is no Prefix+SequenceNumber uniqueness, rule version, idempotency request key, or business aggregate Id.

5. Compile-time metadata

Owner-local allocation fact
// ① The generator collects tenant, soft-delete, and index metadata at compile time.
[BitzTable("SysSequenceNumberGenerateRecord", IsTenant = true, IsSoftDelete = true)]
[BitzIndex(
"UX_SysSequenceNumberRecord_Tenant_Table_Field_SeqStr",
"TenantId", "TableName", "Field", "SequenceNumberStr",
IsUnique = true)]
public sealed class SysSequenceNumberGenerateRecord : BizEntityBase
{
// ② Full string is the database's final uniqueness guard.
[BitzColumn(Length = 128, IsRequired = true)]
public string SequenceNumberStr { get; set; } = string.Empty;
}

Infrastructure consumes only IEntitySet<T> and references no SqlSugar or EF Core adapter.

6. Seed orchestration

StepOrderSeedIdNatural key
Rule700sys_sequence_number_ruleTableName + Field + RuleName
Setting710sys_sequence_number_rule_settingRuleId + Sort

Setting explicitly DependsOn Rule. Both use EntitySetCsvSeedStepBase<T> for row-by-row upserts.

7. Current assets

The rule CSV has a header plus two rows; settings has a header plus six. Every row has TenantId=1000001, IsInternal=true, IsEnabled=true, and IsDeleted=false.

RuleIds are DemoCase-SerialId-demo_case_serial and DemoInvoice-SerialId-demo_invoice_serial, matching runtime construction.

8. Seed update boundary

Rule Copy updates separator, compensation, active state, condition, priority, ConditionScope, description, and base tenant/organization/status fields. It does not change TableName, Field, or RuleName.

Setting Copy updates segment configuration and base fields but not RuleId or Sort. A changed natural key inserts a new row; old rows are not desired-state deleted.

9. CSV strictness

The shared reader disables strict HeaderValidated/MissingFieldFound callbacks and mainly warns on suspicious key columns. Numbering adds no rule-DSL lint.

A successful seed does not prove valid condition JSON, type, date format, branch map, unique Sort, or maximum output length.

10. Host composition

The API Host calls AddBitzOrcasNumberingPlatform:

Current registration
// ① The selected generated ORM adapter provides all three IEntitySet<T> services.
services.AddBitzOrcasGeneratedPersistenceAdapters(persistenceProvider);
// ② Numbering registers one scoped implementation of the Framework port.
services.AddBitzOrcasNumberingPlatform();
// ③ Generated seed manifests contribute both steps to orchestration.
services.AddBitzOrcasGeneratedSeedSteps();

There is no Numbering endpoint map.

11. Feature truth

Governance catalogs one default-enabled numbering.sequence Feature. GenerateAsync injects no feature evaluator, and the module has no endpoint or handler applying a gate.

Catalog presence does not prove that tenant plans can disable generation. A calling business use case must enforce it, or a future port decorator must centralize enforcement.

12. No permission or management surface

There is no PermissionCatalog, rule CRUD, publication, preview, version, approval, or audit. Production changes currently require seed/database operations.

A future management API belongs in Numbering Contracts/Application and must not expose IEntitySet to hosts.

13. Business-owner integration

A business module depends on Framework’s ISequenceNumberGenerator, passes stable TableName/Field plus explicit EntityValues, and never references Numbering persistence records.

Business handler boundary
// ① Include only fields required by conditions and segments.
var values = new Dictionary<string, object?>
{
["OfficeId"] = invoice.OfficeId,
["InvoiceType"] = invoice.TypeCode
};
// ② The Invoice owner implements the optional callback without exposing IQueryable.
var request = new SequenceNumberRequest(
"Invoice", "SerialId", values,
BusinessSerialContext: invoiceSerialContext);
// ③ Persist the allocated string immediately as aggregate state.
var serial = await generator.GenerateAsync(request, cancellationToken);

14. Consumption gap

A global source search finds no business Command constructing SequenceNumberRequest. Registration and tests exist, but there is no evidenced production business path. GA needs at least one tracer-bullet consumer.

15. Inspection commands

Terminal window
# Three tables, indexes, and two seed steps.
rg -n "BitzTable|BitzIndex|SeedId|WhereColumns|DependsOn" src/Platform/Numbering -g '*.cs'
# Production consumption evidence.
rg -n "new SequenceNumberRequest|ISequenceNumberGenerator" src -g '*.cs' --glob '!**/bin/**' --glob '!**/obj/**'

Module overview · Rules and segments

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%