AwadyLab.EFCatalyst
1.0.1
See the version list below for details.
dotnet add package AwadyLab.EFCatalyst --version 1.0.1
NuGet\Install-Package AwadyLab.EFCatalyst -Version 1.0.1
<PackageReference Include="AwadyLab.EFCatalyst" Version="1.0.1" />
<PackageVersion Include="AwadyLab.EFCatalyst" Version="1.0.1" />
<PackageReference Include="AwadyLab.EFCatalyst" />
paket add AwadyLab.EFCatalyst --version 1.0.1
#r "nuget: AwadyLab.EFCatalyst, 1.0.1"
#:package AwadyLab.EFCatalyst@1.0.1
#addin nuget:?package=AwadyLab.EFCatalyst&version=1.0.1
#tool nuget:?package=AwadyLab.EFCatalyst&version=1.0.1
AwadyLab.EFCatalyst
An Entity Framework Core 10 toolkit for the things most line-of-business data layers rebuild by hand: auditable, soft-deletable and multi-tenant entities, named global query filters, LINQ helpers for filtering, sorting and paging, a SaveChanges pipeline, column encryption, change-tracking audit logs and migration helpers for views, triggers, upserts and filtered indexes.
Overview
AwadyLab.EFCatalyst plugs into an ordinary DbContext: entities implement small interfaces (or derive from the
provided bases), the model picks up the matching conventions and filters, and a set of interceptors does the
auditing, tenancy and soft-delete work on every save. Targets .NET 10 and EF Core 10.
There are five packages, and they ship in lockstep:
| Package | What it adds |
|---|---|
AwadyLab.EFCatalyst.Abstraction |
Contracts and entity bases (entity interfaces and base classes, domain events, global filters, seeders, service abstractions) for domain projects. See its README. |
AwadyLab.EFCatalyst |
Every provider-neutral feature in this document (references the abstractions). |
AwadyLab.EFCatalyst.SqlServer |
Native rowversion, deadlock detection, T-SQL for the migration helpers. See its README. |
AwadyLab.EFCatalyst.PostgreSql |
Deadlock detection, PostgreSQL SQL for the migration helpers. See its README. |
AwadyLab.EFCatalyst.Sqlite |
Sortable DateTimeOffset storage, busy/locked detection, SQLite SQL for the migration helpers. See its README. |
Key Highlights
- Entities That Audit Themselves: Implement
ICreationAudited,IModificationAudited,IDeletionAuditedorITenantEntity<T>(or derive fromFullAuditedAggregateRoot<TKey>) and the save pipeline stamps the audit columns, assigns the tenant and turns deletes into soft deletes. - Named Global Filters: Soft delete and tenant isolation are applied as named query filters, so one query can
switch one of them off (
IncludeSoftDeleted,IgnoreTenantFilter) without losing the other. - One SaveChanges Pipeline: Audit, tenant guard, soft delete, concurrency, validation, integrity hashing and domain events run in a single pass that detects changes once and walks the change set once.
- Column Security:
StoreEncrypted(AES-256-GCM),StoreMaskedandStorePermutated, configured with the fluent API only. - Migrations Beyond Tables: Idempotent seed data, upserts, views, functions, filtered and soft-delete indexes, and soft-delete and timestamp triggers, generated per provider.
- Low-Allocation Hot Paths: Per-entity-type metadata is computed once per model; expression trees and reflection are cached; crypto and naming code works on pooled or stack buffers.
- A Tracked Public API: Every public symbol is declared in
PublicAPI.*.txt; everything else is internal.
Installation
dotnet add package AwadyLab.EFCatalyst
dotnet add package AwadyLab.EFCatalyst.SqlServer # or .PostgreSql / .Sqlite, next to the EF Core provider
dotnet add package AwadyLab.EFCatalyst.Abstraction # optional, domain projects that only need the contracts
Quickstart
1. Define an entity
public sealed class Order : FullAuditedAggregateRoot<int>, ITenantEntity<int>
{
public decimal Total { get; private set; }
public int TenantId { get; private set; }
public void Place() => AddDomainEvent(new OrderPlaced(Id));
}
2. Configure the context
public sealed class ShopContext(DbContextOptions<ShopContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
protected override void ConfigureConventions(ModelConfigurationBuilder b) =>
b.ConfigureDecimalPrecision(18, 2).ConfigureDateTimeUtc();
protected override void OnModelCreating(ModelBuilder modelBuilder) =>
modelBuilder.AddDefaultQueryFilters(this); // soft delete + tenant, as named filters
}
3. Register in DI (Program.cs)
services.AddEFCatalyst(o => o.Features.Validation = true);
services.AddScoped<ICurrentUserAccessor, HttpUserAccessor>(); // audit user
services.AddScoped<ICurrentTenantAccessor<int>, HttpTenantAccessor>(); // current tenant, read per query
services.AddScoped<IDomainEventDispatcher, MediatorDispatcher>(); // optional
services.AddDbContext<ShopContext>((sp, o) => o
.UseSqlServer(connectionString)
.UseEFCatalystSqlServer()
.UseEFCatalystInterceptors(sp));
Removing an Order now sets IsDeleted, DeletedAtUtc and DeletedBy; creating and updating stamp the audit
columns; new rows get the context's tenant and writes to another tenant's rows are rejected; the placed event is
dispatched after the save succeeds.
1. Domain Model
Entity interfaces: IEntity<TKey>, ISoftDelete, IDeletionAudited, ICreationAudited, IModificationAudited,
IAuditEntity, IFullAudited, ITenantEntity<T>, IRowVersion, IActiveState, IHashableEntity.
Base classes: Entity, AuditedEntity, SoftDeleteEntity, DeletionAuditedEntity, FullAuditedEntity,
TenantEntity, AggregateRoot, FullAuditedAggregateRoot.
Details: docs/domain.md.
2. Querying
- Conditional filters:
WhereIf,WhereIfNotNull,WhereIfNotNullOrWhiteSpace,WhereIfNotEmpty,WhereExists/WhereNotExists, chunkedWhereIn/WhereNotIn. - Sorting:
OrderByIf/ThenByIf,OrderByProperty,ApplySorting. - Paging:
PageBy,ToPagedListAsync, keysetSlice/ToCursorPageAsync. - Loading and tracking:
IncludeIf,AsNoTrackingIf,IgnoreQueryFiltersIf. - Filter switches:
IncludeSoftDeleted,OnlySoftDeleted,IncludeInactive,IgnoreTenantFilter. - Bulk soft delete:
ExecuteSoftDeleteAsync,ExecuteRestoreAsync. - Hierarchies: recursive
GetDescendantsAsync/GetAncestorsAsync.
Details: docs/querying.md.
3. Interceptors
The save pipeline, slow-query logging, query tagging and deadlock retry.
Details: docs/interceptors.md.
4. Model Building
IGlobalFilter<T> with AddGlobalQueryFilterInterfacesInAssembly, configuration bases, UTC DateTime and
decimal precision conventions.
Details: docs/model-building.md.
5. Column Security
StoreEncrypted (AES-256-GCM), StoreMasked and StorePermutated, configured with the fluent API only.
Details: docs/security.md.
6. Shadow Properties & Change Tracking
Typed shadow accessors, WhereShadowEquals, GetChangedProperties, HasPropertyChanged, GetOriginalValue and
ToAuditEntryList.
Details: docs/change-tracking.md.
7. Schema & Migrations
- Schema:
GetTableName,GetColumnName,GetPrimaryKeys,GetMappedProperties. - Database lifecycle:
EnsureDatabaseDeletedAndRecreatedAsync,HasPendingMigrationsAsync,IMigrationSeeder. - Migration helpers:
InsertDataIfMissing,UpsertData,DeleteDataIfExists, views, functions, filtered and soft-delete indexes, soft-delete and timestamp triggers.
Details: docs/migrations.md.
8. Providers
Enable a provider package next to the EF Core provider:
options.UseSqlServer(cs).UseEFCatalystSqlServer();
options.UseNpgsql(cs).UseEFCatalystPostgreSql();
options.UseSqlite(cs).UseEFCatalystSqlite(); // or UseEFCatalystSqlite(o => ...)
Each provider package registers its own migrations SQL generator. If you replace IMigrationsSqlGenerator
yourself, derive from the EFCatalyst one or call the provider package after your replacement.
Details: docs/providers.md.
9. Performance & Security
- Performance: per-entity-type metadata is computed once per model (runtime annotations); the save pipeline
detects changes once and walks the change set once; expression trees and reflection are cached; crypto and
naming code works on pooled or stack buffers.
AwadyLab.EFCatalyst.Benchmarkscompares the pipeline with plain EF. - Security: values in migration helpers are provider-typed literals and identifiers are always quoted; dynamic sorting only binds public properties; cursors can be HMAC-signed; sensitive columns are redacted from audit entries and never appear in exception messages; query tags are sanitised. See docs/security.md.
Sample App
SampleApp is organised like an application (Domain/, Data/ with configurations, filters and seeders,
Infrastructure/ with the composition root in SampleHost) and runs one scenario per feature area, each on a
freshly seeded database: model, tenancy, auditing, soft-delete, security, integrity, concurrency,
validation, events, change-tracking, querying, hierarchy, seeding, migrations, diagnostics.
dotnet run --project SampleApp # guided tour on SQLite, every scenario
dotnet run --project SampleApp -- tenancy security # selected scenarios
Building
./build.ps1 # build, unit tests, coverage gate (eng/coverage.json) and report in ../coverage-report
./build.ps1 -Pack # also pack and verify the five packages
dotnet test AwadyLab.EFCatalyst.Tests.Integration # SQL Server + PostgreSQL containers (Docker)
License
Package by Mohamed Elawady
Copyright (c) Mohamed Elawady. All rights reserved.
This software is closed source and proprietary. Subject to the terms below,
you are granted a free, worldwide, non-exclusive license to:
- Use this software, in source or compiled (NuGet package) form, in your
own applications, including commercial applications, at no charge.
You may NOT:
- Redistribute, sublicense, sell, or publish this software (or any
modified version of it) as a standalone product, library, or package,
including republishing it under a different name on NuGet.org or any
other package repository.
- Reverse engineer, decompile, or disassemble the compiled package except
to the extent applicable law expressly permits this despite this
limitation.
- Remove or alter any copyright, trademark, or other proprietary notices.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| 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
- AwadyLab.EFCatalyst.Abstraction (>= 1.0.1)
- Microsoft.EntityFrameworkCore (>= 10.0.12)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on AwadyLab.EFCatalyst:
| Package | Downloads |
|---|---|
|
AwadyLab.EFCatalyst.SqlServer
SQL Server support for AwadyLab.EFCatalyst: native rowversion concurrency, deadlock detection and T-SQL generation for the EFCatalyst migration operations (views, upserts, soft-delete and timestamp triggers, filtered indexes). |
|
|
AwadyLab.EFCatalyst.PostgreSql
PostgreSQL (Npgsql) support for AwadyLab.EFCatalyst: deadlock detection and SQL generation for the EFCatalyst migration operations (views, functions, ON CONFLICT upserts, soft-delete and timestamp triggers, filtered indexes). |
|
|
AwadyLab.EFCatalyst.Sqlite
SQLite support for AwadyLab.EFCatalyst: sortable DateTimeOffset storage, busy/locked detection and SQL generation for the EFCatalyst migration operations (views, upserts, soft-delete and timestamp triggers, filtered indexes). |
GitHub repositories
This package is not used by any popular GitHub repositories.