The SharedKernel Entity Framework package provides a layered set ofDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/jordiaragonzaragoza/JordiAragonZaragoza.SharedKernel/llms.txt
Use this file to discover all available pages before exploring further.
DbContext base classes, repository base classes, entity type configurations, and interceptors that enforce DDD conventions — including soft delete, SmartEnum column mapping, concurrency tokens, and Ardalis.Specification query patterns — with minimal boilerplate in your own modules.
DbContext Hierarchy
Three abstractDbContext classes form a hierarchy. You choose the appropriate base depending on the persistence concern your context serves.
BaseContext
The root of the hierarchy. It wires up logging, sensitive-data logging (development only), and configures SmartEnum column conventions for all derived contexts.
EnableSensitiveDataLoggingandEnableDetailedErrorsare activated only whenIHostEnvironment.EnvironmentName == "Development". They are never enabled in production.ConfigureSmartEnum()automatically applies theSmartEnum.EFCorevalue converter to everySmartEnum-derived property discovered in the model.
BaseBusinessModelContext
Extends BaseContext for write-side (command/aggregate) persistence. It registers the SoftDeleteEntitySaveChangesInterceptor via AddInterceptors, which intercepts every SaveChanges call to convert entity deletions into soft-delete flag updates.
BaseBusinessModelContext for your aggregate root contexts — contexts that participate in transactional writes, host IAggregateRoot entities, and need soft-delete behavior.
BaseReadModelContext
Extends BaseContext for the read-side (projections/query). It exposes a Checkpoints DbSet<Checkpoint> used by catch-up subscriptions to track their last processed stream position.
BaseReadModelContext for your read-model / projection contexts — contexts populated by event handlers and queried by the application query bus.
Store Base Classes
Two abstract store classes implement theIUnitOfWork interface and manage database transactions. They are the entry points for executing operations within a resilient execution strategy.
BaseBusinessModelStore
Wraps a BaseBusinessModelContext. Exposes EventableEntities — the set of tracked aggregates that have unpublished domain events — and ExecuteInTransactionAsync<TResponse>, which:
- Creates an EF execution strategy (for transient-fault retry).
- Begins a transaction.
- Executes the supplied
operation. - Commits if
Result.IsSuccess, rolls back otherwise or on exception.
BaseProjectionsStore
Identical contract to BaseBusinessModelStore but wraps a BaseReadModelContext. Used by projection handlers that need transactional writes to the read-model database.
Repository Base Classes
SharedKernel provides three repository tiers underBusinessModel and two under ReadModel, all built on top of Ardalis.Specification.EntityFrameworkCore.
- BusinessModel Repositories
- ReadModel Repositories
BaseReadRepository<TEntity, TId>
A read-only Ardalis Specification repository. Adds a strongly-typed GetByIdAsync(TId id) that uses EntityByIdSpec internally, replacing the raw GetByIdAsync<TIdx> from RepositoryBase.BaseRepository<TAggregate, TId>
Adds full read/write capability by implementing IRangeableRepository<TAggregate, TId> on top of BaseReadRepository. Use this for aggregate root repositories that need to add, update, and delete.BaseCachedSpecificationRepository<TAggregate, TId>
Extends BaseReadRepository and automatically wraps every read operation (GetByIdAsync, ListAsync, FirstOrDefaultAsync, CountAsync, AnyAsync, etc.) in a cache check via ICacheService. Write operations invalidate the relevant cache entries by prefix.Entity Type Configurations
Two abstractIEntityTypeConfiguration<T> implementations provide a consistent Fluent API starting point.
BaseModelTypeConfiguration<TModel, TId>
Sets the primary key to Id:
BaseAggregateRootTypeConfiguration<TAggregateRoot, TId>
Extends BaseModelTypeConfiguration and adds:
Versionas a row version (optimistic concurrency token viaIsRowVersion()).IsDeletedshadow property for soft delete.- Global query filter that excludes soft-deleted rows from all queries.
Soft Delete: SoftDeleteEntitySaveChangesInterceptor
When BaseBusinessModelContext intercepts a SaveChanges call, SoftDeleteEntitySaveChangesInterceptor.UpdateEntities scans the change tracker for entities in the Deleted state. For any entity whose EF model has an IsDeleted shadow property, it:
- Resets
entry.StatetoModified. - Sets
entry.CurrentValues["IsDeleted"] = true.
DbContext.Remove(entity) never issues a DELETE statement — it issues an UPDATE instead.
BaseAggregateRootTypeConfiguration ensures soft-deleted rows are transparently excluded from all EF queries without any extra code in your repositories or handlers.
Metadata Interfaces and Envelopes
ISoftDeletable
ISoftDeletable
Marks a persistence entity as capable of being soft-deleted. Note that
ISoftDeletable exposes a property named IsDelete, while the EF shadow property used by the interceptor and BaseAggregateRootTypeConfiguration is named "IsDeleted" (with a d suffix). The interceptor does not check for this interface — it checks for the "IsDeleted" EF shadow property on each entity type. AggregateEnvelope implements ISoftDeletable for its IsDelete column; the shadow property approach is used directly on aggregate roots configured via BaseAggregateRootTypeConfiguration.IPartitionable
IPartitionable
Marks a persistence entity as multi-tenant / partition-aware by requiring
TenantId and PartitionClientId string properties.AggregateEnvelope<TAggregate, TId>
AggregateEnvelope<TAggregate, TId>
A sealed wrapper that stores an
IAggregateRoot as a JSON document column alongside ISoftDeletable and IPartitionable metadata. Use this when storing aggregates as document blobs in a relational column rather than mapping each property to its own column.ReadModelEnvelope<TReadModel>
ReadModelEnvelope<TReadModel>
Similar to
AggregateEnvelope but for read models. Implements IPartitionable without ISoftDeletable, since read-model rows are typically rebuilt from scratch rather than soft-deleted.Complete Example
The following shows how to create a custom context, a repository, and an entity type configuration for a hypotheticalOrder aggregate.