Themia.Framework.Data.Sequences
0.36.0
dotnet add package Themia.Framework.Data.Sequences --version 0.36.0
NuGet\Install-Package Themia.Framework.Data.Sequences -Version 0.36.0
<PackageReference Include="Themia.Framework.Data.Sequences" Version="0.36.0" />
<PackageVersion Include="Themia.Framework.Data.Sequences" Version="0.36.0" />
<PackageReference Include="Themia.Framework.Data.Sequences" />
paket add Themia.Framework.Data.Sequences --version 0.36.0
#r "nuget: Themia.Framework.Data.Sequences, 0.36.0"
#:package Themia.Framework.Data.Sequences@0.36.0
#addin nuget:?package=Themia.Framework.Data.Sequences&version=0.36.0
#tool nuget:?package=Themia.Framework.Data.Sequences&version=0.36.0
Themia.Framework.Data.Sequences
Atomic, tenant-scoped document numbering. Allocation runs in its own transaction, so the number survives the caller's rollback: gaps are normal, duplicates are not.
services.AddThemiaSequences(o =>
{
o.ConnectionString = builder.Configuration.GetConnectionString("Default")!;
o.Engine = SequenceEngine.Postgres;
});
await sequences.EnsureSequenceAsync("DocNo:Invoice:2026", startValue: 1);
var number = await sequences.NextAsync("DocNo:Invoice:2026"); // 1, then 2, …
Pass this assembly to ThemiaMigrations.Run so the themia_sequences table is created.
Two things to know before adopting
It does not guarantee gapless numbering, and cannot. The value is allocated before your transaction commits; if you roll back, the number is spent. If a regulator requires an unbroken run, this is not the mechanism.
There is no null-tenant fallback. NextAsync throws when there is no ambient tenant. Background jobs
must establish one (BackgroundTenantScope.Begin), or call NextHostAsync when a host-level counter is
genuinely what you want. This is deliberate: a job that lost its tenant scope would otherwise draw every
tenant's numbers from one shared counter with nothing reporting it.
Formatting (INV-2026-00042) is yours. The provider returns a long.
Gapless numbering inside caller's transaction (ITransactionalSequenceAllocator)
When a regulator (such as the Thai Revenue Department for Tax Invoices, Receipts, Withholding Tax Certificates, and Credit Notes) requires an unbroken, strictly gapless run of numbers, use ITransactionalSequenceAllocator:
// Inside your own transaction:
await using var tx = await conn.BeginTransactionAsync(ct);
// Allocates in the caller's transaction; rows on the same key lock until commit/rollback.
var n = await allocator.NextHostInTransactionAsync(tx, $"DocNo:TaxInvoice:{period}", ct);
// Do your document inserts here...
// If anything fails or rolls back, the counter increment rolls back too -> no gap!
await tx.CommitAsync(ct);
NextInTransactionAsync(tx, key, ct): Tenant-scoped inside the caller's transaction (requires ambient tenant).NextHostInTransactionAsync(tx, key, ct): Host-level inside the caller's transaction.- Lazy seeding: Seeds starting at 1 on first use race-free (unlike
ISequenceProvider, which throws when an unseeded key is accessed). No priorEnsureSequenceAsynccall required. - Pre-seeding existing runs: Calling
EnsureSequenceAsync(key, startValue)(orEnsureHostSequenceAsync) beforehand is fully supported if you need an initial offset other than 1. - Shared table caution: Both mechanisms share
themia_sequences. Never callISequenceProvider.Next*on a key meant for gapless transactional numbering, as its separate transaction will cause skipped numbers. - Database & connection: The allocator ignores
SequenceOptions.ConnectionStringand runs directly ontx.Connection. Ensurethemia_sequencesexists in the caller's database (viaSequencesSchemaMigration) andSequenceOptions.Enginematches the caller's database engine. - Transaction isolation: Caller transactions must use
ReadCommitted. UnderRepeatableReadorSerializableon PostgreSQL, queued callers fail with 40001 upon the previous holder's commit. On MySQL, defaultREPEATABLE READrisks gap-lock deadlocks during first-use inserts.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Dapper (>= 2.1.79)
- FluentMigrator (>= 8.0.1)
- Microsoft.Data.SqlClient (>= 6.1.5)
- Microsoft.Extensions.Caching.Memory (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection (>= 10.0.9)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Options (>= 10.0.9)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.19.1)
- Microsoft.IdentityModel.Logging (>= 8.19.1)
- Microsoft.IdentityModel.Protocols (>= 8.19.1)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 8.19.1)
- Microsoft.IdentityModel.Tokens (>= 8.19.1)
- MySqlConnector (>= 2.6.0)
- Npgsql (>= 10.0.3)
- System.IdentityModel.Tokens.Jwt (>= 8.19.1)
- System.Security.Cryptography.Pkcs (>= 10.0.13)
- Themia.Framework.Core (>= 0.36.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Themia.Framework.Data.Sequences:
| Package | Downloads |
|---|---|
|
Themia.ETax.Data
Database helpers for Themia.ETax: the required immutability trigger and same-seller replacement key (FluentMigrator, PostgreSQL) for an app's own tax document table, and the gapless document-number source over Themia's transactional sequence allocator. |
|
|
Themia.ETax.Withholding.Data
Database helpers for Themia.ETax.Withholding: the required immutability trigger, same-payer replacement key and issue-key uniqueness (FluentMigrator, PostgreSQL) for an app's own withholding certificate table, and the gapless certificate-number source over Themia's transactional sequence allocator. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.36.0 | 0 | 10/23/2026 |
| 0.35.3 | 0 | 10/22/2026 |
| 0.35.2 | 78 | 10/20/2026 |
| 0.35.1 | 118 | 10/17/2026 |
| 0.35.0 | 96 | 10/17/2026 |
| 0.34.0 | 99 | 10/17/2026 |
| 0.33.0 | 141 | 10/17/2026 |
| 0.32.0 | 90 | 10/15/2026 |
| 0.31.3 | 127 | 10/14/2026 |
| 0.31.2 | 91 | 10/13/2026 |
| 0.31.1 | 88 | 10/13/2026 |
| 0.31.0 | 75 | 10/13/2026 |
| 0.30.5 | 103 | 10/13/2026 |
| 0.30.4 | 99 | 10/4/2026 |
| 0.30.3 | 95 | 10/4/2026 |
| 0.30.2 | 94 | 10/3/2026 |
| 0.30.1 | 103 | 9/27/2026 |
| 0.30.0 | 104 | 9/27/2026 |
| 0.29.0 | 106 | 9/19/2026 |
| 0.28.1 | 108 | 9/19/2026 |