Skip to main content
Version: Latest

8. Reference Data De-gating

8.1 What changed

Sixteen ApplicationDbSeeder (Shumoul.Infrastructure/Persistence/Initialization/ApplicationDbSeeder.cs) seed steps were removed from the one-time ExecuteSeedIfNeededAsync/SeedsHistory gate and are now called directly, unconditionally, on every SeedDatabaseAsync invocation:

MethodMatching key (already existing, unchanged)
SeedCurrenciesAsyncName == entity.Name && CurrencyCode == entity.CurrencyCode
SeedChartofAccountsAsyncCode
SeedPaymentMethodsAsyncName == entity.Name && PaymentType == entity.PaymentType
SeedLookupGroupsAsyncCode
SeedAddressTypesAsyncFName
SeedDeviceTypesAsyncDeviceTypeCode
SeedDeviceModelsAsyncCode
SeedBarcodeLabelFieldsAsyncField
SeedBarcodeLabelTemplatesAsyncName (see §8.2 — this check was buggy)
SeedBarcodeLabelTemplateFieldsAsync(BarcodeLabelTemplateId, BarcodeLabelFieldId)
SeedMonthsAsyncNo
SeedZatcaCreditDebitNoteReasonCodesAsyncCode
SeedZatcaDocumentTypeCodesAsyncCode
SeedZatcaIdentityTypeCodesAsyncCode
SeedZatcaInvoiceCategoriesAsyncCode
SeedZatcaTaxCategoriesAsyncCode
SeedZatcaTaxCategoryReasonsAsyncCode

Every one of these already had a real, correct per-row matching key before this phase — de-gating them only required removing the wrapper; no seeding logic itself needed to change (aside from the one bug below). This means: new rows added to any of these JSON files later reach every tenant on the next startup/re-provisioning, instead of being silently stuck behind a SeedsHistory row created on the very first deploy.

Not de-gated (deliberately unchanged, still one-time-gated): SeedBranchesAsync, SeedWarehousesAsync, SeedDeviceAsync — see Chapter 3 §3.3.

8.2 Bug found and fixed: SeedBarcodeLabelTemplatesAsync's existence check

The pre-existing check was:

if (dbContext.BarcodeLabelFields.FirstOrDefault(x => x.Name == barcodeLabelTemplate.Name) is null)

This queries BarcodeLabelFields (a different table entirely) instead of BarcodeLabelTemplates — since a BarcodeLabelField's Name never coincides with a template's Name, this check always returned "not found," meaning a re-run of this seeder (had it ever been re-invoked) would have duplicated every template on every call. Under the old one-time gate this was latent and harmless (the method only ever ran once); de-gating it would have exposed the bug immediately (a growing set of duplicate templates on every tenant DB re-provisioning), so it was fixed as a required part of this phase:

if (dbContext.BarcodeLabelTemplates.FirstOrDefault(x => x.Name == barcodeLabelTemplate.Name) is null)

8.3 Live confirmation

During manual verification (see Chapter 9), the de-gated steps were observed running across every already-provisioned tenant's database at host startup (Hangfire re-runs ApplicationDbSeeder.SeedDatabaseAsync for every active tenant on process start) — consistently reporting Inserted=0 on tenants that already had every row, confirming both idempotency and that no duplicates were produced.