Kandra.Persistence.Abstractions
Kandra.Persistence.Abstractions.Accounting.AccountQueryServiceExtensions
Methods
| Method | Description |
|---|---|
GetTransactionsInvolvingAsync(IAccountQueryService, IReadOnlyList<AccountCode>, IReadOnlyList<IRootEntity>, Nullable<DateTime>, Nullable<DateTime>, Boolean, CancellationToken) | "Either side" convenience - matches if the account/subconto filters hit source OR destination. Implemented as two workhorse calls unioned by Id, since the workhorse itself only expresses AND between its source and destination filters. |
Kandra.Persistence.Abstractions.Accounting.IAccountBalanceUpdater
Methods
| Method | Description |
|---|---|
ApplyAsync(IReadOnlyList<PostingTransactionRecord>, CancellationToken) | Applies the effect of exactly these lines - not a whole batch. The caller passes only the Activated rows from a PostingMergeResult: lines that were unchanged by a merge never reach here at all, so an unchanged re-post touches zero AccountBalance rows. |
RevertAsync(IReadOnlyList<PostingTransactionRecord>, CancellationToken) | The exact inverse of ApplyAsync - subtracts what a prior ApplyAsync(lines) added. The caller passes the Deprecated rows from a PostingMergeResult here. |
Kandra.Persistence.Abstractions.Accounting.IAccountQueryService
Methods
| Method | Description |
|---|---|
GetBalancesAsync(IReadOnlyList<AccountCode>, IReadOnlyList<IRootEntity>, CancellationToken) | Workhorse balance query. At least one of accounts/subconto must be given - specifying neither would mean "every balance row in the system," which is never what a caller actually wants and is rejected rather than silently allowed. accounts: restricts to these accounts (any one of them matches - OR). subconto: restricts to balances carrying these subconto values. Values of the SAME concrete type are OR'd together (e.g. "any of these three counterparties"); values of DIFFERENT types are AND'd together (e.g. "this counterparty AND this item, on the same balance row"). Mixing both accounts and subconto ANDs the two filters together. |
GetTransactionsAsync(IReadOnlyList<AccountCode>, IReadOnlyList<IRootEntity>, IReadOnlyList<AccountCode>, IReadOnlyList<IRootEntity>, Nullable<DateTime>, Nullable<DateTime>, Boolean, CancellationToken) | Workhorse movement query. Unlike GetBalancesAsync, source and destination are independent filter pairs, ANDed together when both sides are given. Leave a side's filters null to not constrain that side at all; at least one of the four filter parameters must be given. For the common "either side" case, see GetTransactionsInvolvingAsync (AccountQueryServiceExtensions) rather than passing the same values to both sides here - that would AND them, not OR. includeDeprecated: by default only currently-active lines are returned - set true for an audit/history view that also shows lines that were later corrected or removed. |
Kandra.Persistence.Abstractions.Accounting.IPostingRepository
Kandra-owned, interface only - EF implementation lives in Kandra.Persistence. Deliberately has no transaction-management method - opening/committing a transaction is the calling use case's responsibility, not something this repository decides on its behalf; it only knows how to read/write posting data against whatever DbContext/transaction context it's given.
Methods
| Method | Description |
|---|---|
DeprecateAllAsync(Guid, CancellationToken) | Deprecates every currently-active row of a document's posting batch, e.g. when the document itself is unsubmitted. Safe no-op (returns []) if the document has no batch yet or no active rows - mirrors the register engine's idempotent Unpost pattern. Stages changes into the DbContext's change tracker only - does NOT call SaveChangesAsync, same convention as PrepareMergedBatchAsync. |
GetTransactionsAsync(Guid, CancellationToken) | Every transaction (active AND deprecated) ever posted for a document's batch, ordered by CreatedAtUtc/LineId - a read-only surface for a document-scoped viewer. Empty list if the document has no batch yet. Read-only (AsNoTracking) - unlike the other two members here, this never stages a change into the tracker. |
PrepareMergedBatchAsync(Guid, DateTime, String, IReadOnlyList<PostingTransactionRecord>, CancellationToken) | Merges the given candidate rows into the document's batch - creating the batch if it doesn't exist yet, otherwise deprecating changed/removed rows and activating new ones in their place, correlated by LineId. candidates are unpersisted PostingTransactionRecord instances with content fields already set by IPostingService - Id/BatchId/IsActive/CreatedAtUtc are assigned here, only for the ones that actually get activated. Returns HasChanges = false, with empty Deprecated/Activated, if every line already matched - no write occurs in that case. Stages changes into the DbContext's change tracker only - does NOT call SaveChangesAsync. This repository doesn't own the transaction or the save boundary, so it doesn't decide when to flush either. The caller is responsible for eventually calling SaveChangesAsync. |
Kandra.Persistence.Abstractions.Accounting.ISubcontoResolutionService
Resolves the subconto (TypeId -> EntityIds) groups an IAccountTransactionsReader collected into display data - dictionary-kind subconto (Item/Counterparty/Warehouse/...) via the existing ILookupRepository, document-kind subconto (Waybill/GoodsReceipt/...) some other, configuration-owned way. Kandra-owned interface only, deliberately configuration-specific to implement: which concrete CLR types exist for a given TypeId is only known one layer up, in the consuming configuration (e.g. KandraWms.Persistence.Accounting.SubcontoResolutionService) - the engine has no closed set of ISubconto types to dispatch over itself.
Kandra.Persistence.Abstractions.Accounting.ResolvedSubconto
In-process-only shape (mirrors Kandra.Persistence.Abstractions.Registers.RawFieldValue's own convention) - raw resolved data only, no formatting/localization here. Kind is implied: Reference set means dictionary-kind; DocumentCode set means document-kind. Formatting/localization into the wire Kandra.Forms.Accounting.SubcontoValueDto happens in the Application-layer orchestrator (Kandra.Application.Services.Accounting.AccountTransactionsService), same split RawRegisterTransactionRow -> RegisterTransactionsMapper already uses.
Constructors
| Constructor | Description |
|---|---|
ResolvedSubconto(String, Boolean, CodeNameRef, String, Nullable<DateTime>) | In-process-only shape (mirrors Kandra.Persistence.Abstractions.Registers.RawFieldValue's own convention) - raw resolved data only, no formatting/localization here. Kind is implied: Reference set means dictionary-kind; DocumentCode set means document-kind. Formatting/localization into the wire Kandra.Forms.Accounting.SubcontoValueDto happens in the Application-layer orchestrator (Kandra.Application.Services.Accounting.AccountTransactionsService), same split RawRegisterTransactionRow -> RegisterTransactionsMapper already uses. |
Kandra.Persistence.Abstractions.Blobs.BlobStorageOptions
Properties
| Property | Description |
|---|---|
InlineStorageThresholdBytes | undocumented |
Kandra.Persistence.Abstractions.Blobs.IBlobContentStore
Raw byte storage abstraction - purely bytes in, bytes out, keyed by an opaque storageKey (the sharded on-disk/object-store key, AD-12). No business logic here; only invoked at all when content exceeds the inline-storage threshold (AD-11) - small content never reaches this.
Methods
| Method | Description |
|---|---|
DeleteAsync(String, CancellationToken) | undocumented |
Kandra.Persistence.Abstractions.Blobs.IBlobRepository
Plain persistence gateway for the blob storage subsystem - EF implementation lives in Kandra.Persistence. Business logic (dedup, TTL/tombstone computation, entity-reference reconciliation) lives in IBlobService (Kandra.Application.Abstractions), which is the only consumer. Stages changes into the DbContext's change tracker only - never calls SaveChangesAsync, same convention as ISettingsRepository/IPostingRepository; the caller decides when to flush.
Methods
| Method | Description |
|---|---|
DeletePurgeableReferencesAsync(DateTime, CancellationToken) | undocumented |
FindBlobByHashAsync(String, CancellationToken) | undocumented |
GetExpiredActiveReferencesAsync(DateTime, CancellationToken) | undocumented |
GetExtendedAsync<T0>(Func<IQueryable<BlobReference>, IQueryable<T0>>, Int32, Int32, CancellationToken) | undocumented |
GetOrphanBlobsAsync(CancellationToken) | undocumented |
GetReferenceAsync(Guid, Boolean, CancellationToken) | undocumented |
Kandra.Persistence.Abstractions.IDataSeeder
A module/configuration-registered seed step, run automatically by the engine's DatabaseSeeder after identity/role/claims seeding. Register one implementation per independent seed concern (e.g. a dictionary's reference data, a default constant) via services.AddScoped<IDataSeeder, YourSeeder>() — no ordering is guaranteed across different registered seeders.
Kandra.Persistence.Abstractions.IEntityRepository<T0>
Methods
| Method | Description |
|---|---|
ExecuteUpdateAsync(Func<IQueryable<T0>, IQueryable<T0>>, Action<UpdateSettersBuilder<T0>>, CancellationToken) | undocumented |
GetExtendedLookupAsync<T0>(Func<IQueryable<T0>, IQueryable<T0>>, Int32, Int32, CancellationToken) | undocumented |
Touch(T0, Guid) | undocumented |
Kandra.Persistence.Abstractions.ILookupRepository
Methods
| Method | Description |
|---|---|
GetDictionaryAsync<T0>(Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | undocumented |
GetDocumentsAsync(Func<IQueryable<DocumentBase>, IQueryable<DocumentBase>>, CancellationToken) | undocumented |
GetDocumentTypeIdAsync(Guid, CancellationToken) | undocumented |
Kandra.Persistence.Abstractions.Linking.IDocumentLinkRepository
Plain persistence gateway for Document Links - EF implementation lives in Kandra.Persistence. Diff/sync logic lives in IDocumentLinkService (Kandra.Application.Abstractions), the only consumer. Stages changes into the DbContext's change tracker only - never calls SaveChangesAsync, same convention as IBlobRepository/IPostingRepository; the caller decides when to flush.
Kandra.Persistence.Abstractions.Registers.BalanceReaderExtensions
Dimension-key-set overload for IBalanceReader — same rationale as TurnoverReaderExtensions: an extension method rather than an interface member, extra type parameters inferred from the caller's concrete closed TBalance.
Methods
| Method | Description |
|---|---|
Balances<T0, T1, T2, T3>(IBalanceReader<T0, T1>, IReadOnlyCollection<T2>, Func<IQueryable<T1>, IQueryable<T1>>, CancellationToken) | Current balances, restricted to dimensionKeys. Batches the key set and composes each batch's filter with adjust, delegating to the existing Balances. |
Kandra.Persistence.Abstractions.Registers.DimensionPredicateBuilder
Builds an EF-translatable WHERE filter over a set of dimension keys — (d1) OR (d2) OR ..., each term from BuildEqualityPredicate rebound onto the caller-supplied Dimensions selector. No reflection: the selector is compile-time-typed per caller, and each dimensions class hand-writes its own equality predicate.
Methods
| Method | Description |
|---|---|
BuildOr<T0, T1>(Expression<Func<T0, T1>>, IReadOnlyCollection<T1>) | One OR-of-equality predicate over all keys, or null when there are none (nothing to filter on). For large key sets, prefer BuildOrBatches to stay under provider parameter limits. |
BuildOrBatches<T0, T1>(Expression<Func<T0, T1>>, IReadOnlyCollection<T1>, Int32) | keys split into fixed-size batches (default 200 — chosen against SQL Server's ~2100 query-parameter cap, the tightest of this codebase's live providers), each yielded as its own OR predicate. Callers run one query per batch and merge results — batches partition keys with no overlap, so no cross-batch merge logic is needed beyond concatenation. |
Kandra.Persistence.Abstractions.Registers.IBalanceReader<T0, T1>
Balance registers add the current-balance projection on top of the movements log.
Methods
| Method | Description |
|---|---|
Balances(DateTime, Func<IQueryable<T1>, IQueryable<T1>>, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | As-of-date balances (design §9.1): current balance minus the effective sum of movements with Period > at — "current − tail", computed here (not by the caller). adjustBalances/adjustMovements each shape their own half of the read exactly like Balances/ Movements do. Unlike those, this overload has no projected-result sibling: the internal aggregation needs the real TBalance/TMovement shape (Dimensions, Resources, IsExpense), so Include() is how the caller pulls in navigation it wants on the resulting rows' Dimensions. |
Balances(Func<IQueryable<T1>, IQueryable<T1>>, CancellationToken) | Current balances, materialized. adjust works exactly like Movements's — filters, sorting, Include()s for navigation the caller needs after materialization. |
Balances<T0>(Func<IQueryable<T1>, IQueryable<T0>>, CancellationToken) | Same read, but project shapes the result directly instead of returning TBalance entities — see Movements for why that means no Include() is needed for navigation the projection itself dereferences. |
Kandra.Persistence.Abstractions.Registers.IBalanceRegisterWriter<T0, T1>
Same write surface as ITurnoverRegisterWriter, but commit also maintains the register's balance table: delta upserts, each touched balance guarded by its resources' own EnsureNonNegative.
Kandra.Persistence.Abstractions.Registers.IDocumentInfoRegisterWriter<T0>
Posting surface for a document-bound information register. Resolvable only from document-posting code — a register contributes no other write path. No balance to maintain, so this is a plain replace-by-recorder log, simpler than ITurnoverRegisterWriter's balance counterpart despite the similar shape.
Methods
| Method | Description |
|---|---|
DeleteAsync(Guid, CancellationToken) | Unposts (if needed) and then physically removes the document's records — the register-side half of document deletion. |
PostAsync(Guid, DateTime, IReadOnlyCollection<T0>, CancellationToken) | Replaces the record set for documentId with records, atomically. |
UnpostAsync(Guid, CancellationToken) | Deactivates the document's current record set (unpost). Rows remain in the log with Active = false. |
Kandra.Persistence.Abstractions.Registers.IInfoRegisterReader<T0>
Reader for a periodic information register — either write mode (independent or document-bound share this same read surface): raw records for a period, plus the "latest value as of date" slice — the killer query for info registers (design §9, §11).
Methods
| Method | Description |
|---|---|
Records(DateTime, DateTime, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Raw records in a period, materialized — journals, drill-down. adjust lets the caller extend the query before it runs — extra filters, sorting, Include()s for navigation read after materialization. Returned rows are already AsNoTracking()'d — this is a terminal read, not a further- composable IQueryable. |
Records<T0>(DateTime, DateTime, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Same read, but project shapes the result directly instead of returning TRecord entities. |
SliceOfLast(DateTime, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Latest record per dimension combination with Period <= at, materialized. adjust narrows the candidate rows before the (necessarily client-side — owned-type GroupBy doesn't translate to SQL) grouping runs, same purpose as Records's. |
Kandra.Persistence.Abstractions.Registers.IInfoRegisterWriter<T0, T1, T2>
Write surface for a periodic information register's independent write mode (design §11): rows are edited directly — imports, admin UI, dictionary behaviors — rather than only through document posting. Unlike IDocumentInfoRegisterWriter, this is registered directly in the container (info registers are reference-style data; the document-only restriction applies to accumulation and document-bound registers, not this tier). Uniqueness is enforced on dimensions + period; SetAsync upserts.
Methods
| Method | Description |
|---|---|
DeleteAsync(T1, DateTime, CancellationToken) | Removes the record for dimensions/period, if any. |
SetAsync(T1, DateTime, T2, CancellationToken) | Creates or overwrites the record for dimensions/period with details. |
Kandra.Persistence.Abstractions.Registers.IRegisterMaintenance<T0, T1>
Admin/diagnostic operations over a balance register: rebuild the balance table from the movements log, or verify it matches without writing.
Methods
| Method | Description |
|---|---|
RebuildAsync(CancellationToken) | Truncates the balance table and recomputes it from active movements. Design §8.5. |
VerifyAsync(CancellationToken) | Recomputes balances from active movements and diffs against what's currently persisted, without writing. |
Kandra.Persistence.Abstractions.Registers.IRegisterReader
Root marker for every register reader interface. Carries no members - it exists so ISubmitScope.GetReader<TReader>() (Kandra.Application.Abstractions.Services) can constrain its generic parameter to actual reader types instead of any class, the same role IRegisterWriter plays for ISubmitScope.GetWriter<TWriter>().
Kandra.Persistence.Abstractions.Registers.IRegisterTransactionsReader<T0>
Reads one register row type's movements/document-info-records for one document id, resolved into the register-transactions viewer's in-process shape. One closed implementation per register row type is generated by Kandra.Generators.RegisterTransactions.Persistence — see that generator's own doc comment for why this can't be a single open-generic engine class the way ITurnoverReader is: dictionary-reference dimension resolution needs to know, per property, which ones are FKs and to which dictionary type, a fact only available at generator time (reflection would work too, but this codebase's registers deliberately avoid reflection-based dimension handling — see DimensionPredicateBuilder's own precedent).
Properties
| Property | Description |
|---|---|
Shape | Compile-time-known shape (captions/kinds) — no database access. |
Kandra.Persistence.Abstractions.Registers.IRegisterWriter
Root marker for every register writer interface. Carries no members - it exists so ISubmitScope.GetWriter<TWriter>() (Kandra.Application.Abstractions.Services) can constrain its generic parameter to actual writer types instead of any class.
Kandra.Persistence.Abstractions.Registers.ITurnoverReader<T0>
Base reader for any accumulation register: raw movements for a period — journals, drill-down, custom aggregation via ordinary LINQ.
Methods
| Method | Description |
|---|---|
Movements(DateTime, DateTime, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Movements for a period, materialized. adjust lets the caller extend the query before it runs — extra filters, sorting, and any Include()s for navigation the caller will read after materialization (e.g. q => q.Include(m => m.Dimensions.Storage)). Returned rows are already AsNoTracking()'d — this is a terminal read, not a further- composable IQueryable. |
Movements<T0>(DateTime, DateTime, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Same read, but project shapes the result directly (e.g. into a report row) instead of returning TMovement entities — the projection composes into the same SQL query, so navigation it dereferences (m.Dimensions.Storage.Name) needs no Include(): no reason to fetch whole related entities when the caller only wants a couple of their columns. |
Kandra.Persistence.Abstractions.Registers.ITurnoverRegisterWriter<T0>
Posting surface for an accumulation register. Resolvable only from document-posting code — a register contributes no other write path.
Methods
| Method | Description |
|---|---|
DeleteAsync(Guid, CancellationToken) | Unposts (if needed) and then physically removes the document's movement rows — the register-side half of document deletion. |
PostAsync(Guid, DateTime, IReadOnlyCollection<T0>, CancellationToken) | Replaces the record set for documentId with movements and commits it atomically (design §8.2): stamps engine-managed headers, computes the balance delta against the previous set, and applies it. |
UnpostAsync(Guid, CancellationToken) | Deactivates the document's current record set (unpost) and applies the reversing delta. Rows remain in the log with Active = false. |
Kandra.Persistence.Abstractions.Registers.InfoRegisterReaderExtensions
Dimension-key-set overload for IInfoRegisterReader — same rationale as TurnoverReaderExtensions: an extension method rather than an interface member, extra type parameters inferred from the caller's concrete closed TRecord.
Methods
| Method | Description |
|---|---|
Records<T0, T1, T2>(IInfoRegisterReader<T0>, DateTime, DateTime, IReadOnlyCollection<T1>, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Records for a period, restricted to dimensionKeys. |
SliceOfLast<T0, T1, T2>(IInfoRegisterReader<T0>, DateTime, IReadOnlyCollection<T1>, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Latest record per dimension combination with Period <= at, restricted to dimensionKeys. Batches partition dimensionKeys with no overlap, so each batch's client-side "latest per dimension" grouping is already final — concatenating batch results needs no further merge. |
Kandra.Persistence.Abstractions.Registers.RawFieldValue
One field's raw value on one row — exactly one of RawValue/Reference/ DocumentReference is set. Reference is set for a Dictionary-kind field, or a DynamicReference field whose row resolved to a Dictionary candidate; DocumentReference is set for a Document-kind field (not yet implemented as a static Kind — see Document's own doc comment) or a DynamicReference field whose row resolved to a Document candidate.
Constructors
| Constructor | Description |
|---|---|
RawFieldValue(String, Object, CodeNameRef, CodeDateRef, String) | One field's raw value on one row — exactly one of RawValue/Reference/ DocumentReference is set. Reference is set for a Dictionary-kind field, or a DynamicReference field whose row resolved to a Dictionary candidate; DocumentReference is set for a Document-kind field (not yet implemented as a static Kind — see Document's own doc comment) or a DynamicReference field whose row resolved to a Document candidate. |
Kandra.Persistence.Abstractions.Registers.RawRegisterTransactionRow
One resolved row, still in-process (never serialized directly — RawValue is a boxed CLR value, formatted to a wire-safe string only by the aggregator, Kandra.Generators.RegisterTransactions.Application's generated output).
Constructors
| Constructor | Description |
|---|---|
RawRegisterTransactionRow(Guid, DateTime, Guid, Boolean, Nullable<Boolean>, IReadOnlyList<RawFieldValue>, IReadOnlyList<RawFieldValue>, IReadOnlyList<RawFieldValue>) | One resolved row, still in-process (never serialized directly — RawValue is a boxed CLR value, formatted to a wire-safe string only by the aggregator, Kandra.Generators.RegisterTransactions.Application's generated output). |
Kandra.Persistence.Abstractions.Registers.RegisterDrift
Result of comparing recomputed balances against the currently persisted ones.
Constructors
| Constructor | Description |
|---|---|
RegisterDrift(Int32, Int32, Int32) | Result of comparing recomputed balances against the currently persisted ones. |
Kandra.Persistence.Abstractions.Registers.RegisterFieldShape
One Dimensions/Resources/Details property's declared shape.
Constructors
| Constructor | Description |
|---|---|
RegisterFieldShape(String, String, Boolean, RegisterFieldKind, Nullable<Guid>, String) | One Dimensions/Resources/Details property's declared shape. |
Kandra.Persistence.Abstractions.Registers.RegisterRowShape
One register row type's declared field shape — mirrors RegisterTransactionsDto's own meta fields, minus the actual rows.
Constructors
| Constructor | Description |
|---|---|
RegisterRowShape(String, String, Boolean, IReadOnlyList<RegisterFieldShape>, IReadOnlyList<RegisterFieldShape>, IReadOnlyList<RegisterFieldShape>) | One register row type's declared field shape — mirrors RegisterTransactionsDto's own meta fields, minus the actual rows. |
Kandra.Persistence.Abstractions.Registers.SubmitScopeKeys
Key writer implementations (and IPostingService) are registered under, so they resolve only through Kandra.Application.Services.SubmitScope, never via plain constructor injection. Lives here (not next to SubmitScope in Kandra.Application) because the keyed writer registrations themselves are made from Kandra.Persistence (RegisterServiceCollectionExtensions) - this is the one project both registration sites (Persistence for writers, Application for IPostingService/SubmitScope itself) already reference.
Kandra.Persistence.Abstractions.Registers.SubmitScopeServiceCollectionExtensions
Public registration surface for the keyed DI slot SubmitScopeKeys gates - lets a register writer, IPostingService, or a test double be registered under the exact key ISubmitScope resolves against, without the caller ever needing to know (or be granted friend access to) the internal ScopeOnly value itself.
Methods
| Method | Description |
|---|---|
AddSubmitScopeService<T0>(IServiceCollection, Func<IServiceProvider, Object, T0>) | Registers implementationFactory as TService under the submit-scope key - for a test double or any other instance that isn't resolved via its own DI-constructible type. |
AddSubmitScopeService<T0, T1>(IServiceCollection) | Registers TImplementation as TService under the submit-scope key - the keyed counterpart to a plain AddScoped<TService, TImplementation>(). |
Kandra.Persistence.Abstractions.Registers.TurnoverReaderExtensions
Dimension-key-set overload for ITurnoverReader — kept as extension methods rather than interface members so TurnoverReader<TMovement> can stay a single open-generic DI registration (it deliberately isn't generic over TDimensions). The extra type parameters are inferred from the caller's concrete closed TMovement at every real call site.
Methods
| Method | Description |
|---|---|
Movements<T0, T1, T2, T3>(ITurnoverReader<T0>, DateTime, DateTime, IReadOnlyCollection<T1>, Func<IQueryable<T0>, IQueryable<T0>>, CancellationToken) | Movements for a period, restricted to dimensionKeys. Batches the key set (see BuildOrBatches) and composes each batch's filter with adjust, delegating to the existing Movements. |
Kandra.Persistence.Abstractions.Scheduling.ISchedulerRepository
Plain persistence gateway for the job scheduler (ScheduledJobDefinition/ScheduledJobRun) - EF implementation lives in Kandra.Persistence. Application-layer scheduler services (SchedulerAdminService/ SchedulerBootstrapService/SchedulerHistoryListener) are the only consumers and never touch a DbContext directly. Mutation methods only stage changes into the DbContext's change tracker - they never call SaveChangesAsync themselves; the caller flushes via IUnitOfWork.SaveAsync, same convention as IBlobRepository/EntityRepository<T>.
Methods
| Method | Description |
|---|---|
QueryJobDefinitionsAsync(Int32, Int32, CancellationToken) | Paged listing for the admin Schedule grid - GetAllJobDefinitionsAsync stays unpaged for the engine's own internal callers (dashboard summary, bootstrap), which always need the full set. |