CSharpEssentials.EntityFrameworkCore 3.0.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package CSharpEssentials.EntityFrameworkCore --version 3.0.2
                    
NuGet\Install-Package CSharpEssentials.EntityFrameworkCore -Version 3.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CSharpEssentials.EntityFrameworkCore" Version="3.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CSharpEssentials.EntityFrameworkCore" Version="3.0.2" />
                    
Directory.Packages.props
<PackageReference Include="CSharpEssentials.EntityFrameworkCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CSharpEssentials.EntityFrameworkCore --version 3.0.2
                    
#r "nuget: CSharpEssentials.EntityFrameworkCore, 3.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CSharpEssentials.EntityFrameworkCore@3.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CSharpEssentials.EntityFrameworkCore&version=3.0.2
                    
Install as a Cake Addin
#tool nuget:?package=CSharpEssentials.EntityFrameworkCore&version=3.0.2
                    
Install as a Cake Tool

CSharpEssentials.EntityFrameworkCore

CSharpEssentials.EntityFrameworkCore offers a set of extensions, interceptors, and base classes to enhance Entity Framework Core development. It includes robust pagination support, audit trails, domain event dispatching, slow query logging, and simplified DbContext configuration.

Features

  • Audit Interceptor: Automatically populates CreatedAt/CreatedBy/UpdatedAt/UpdatedBy fields and handles soft deletes.
  • Domain Event Interceptor: Collects and dispatches domain events raised by entities, with before/after save timing and optional outbox pattern support.
  • Slow Query Logging: SlowQueryInterceptor to automatically log queries exceeding a configurable threshold.
  • Advanced Pagination: Extension methods for Offset-based and Cursor-based pagination on IQueryable.
  • BaseDbContext: A base class (BaseDbContext<T>) with built-in logging and scope management.
  • Model Configuration: Extensions to apply configurations easily.

Installation

dotnet add package CSharpEssentials.EntityFrameworkCore

Usage

1. Audit Interceptor

Automatically tracks who created, modified, or deleted entities and when.

using CSharpEssentials.EntityFrameworkCore.Interceptors;

// Simple registration — no need to create a separate class
services.AddAuditInterceptor(() => "system-user");

// Or resolve user ID from DI (e.g. from HttpContext)
services.AddAuditInterceptor(sp =>
    sp.GetRequiredService<IHttpContextAccessor>()
      .HttpContext?.User?.FindFirst("sub")?.Value ?? "anonymous");

// Generic variant for typed user IDs
services.AddAuditInterceptor<Guid>(sp =>
    sp.GetRequiredService<ICurrentUserService>().UserId);

// Register with DbContext
services.AddDbContext<MyDbContext>((sp, options) =>
    options.UseSqlServer(connectionString)
           .AddInterceptors(sp.GetRequiredService<AuditInterceptor>()));

The interceptor handles:

  • Added entities (ICreationAudit) — sets CreatedAt and CreatedBy
  • Modified entities (IModificationAudit) — sets UpdatedAt and UpdatedBy
  • Deleted entities (ISoftDeletable) — converts to soft delete with DeletedAt, DeletedBy, and IsDeleted

2. Domain Event Interceptor

Collects domain events raised by entities and dispatches them during SaveChanges.

using CSharpEssentials.EntityFrameworkCore.Interceptors;

// Register publisher and interceptor
services.AddSingleton<IDomainEventPublisher, MediatRDomainEventPublisher>();
services.AddSingleton<DomainEventInterceptor>();

services.AddDbContext<MyDbContext>((sp, options) =>
    options.UseSqlServer(connectionString)
           .AddInterceptors(sp.GetRequiredService<DomainEventInterceptor>()));
Event Timing

Control when events are published relative to the database save:

using CSharpEssentials.Entity;
using CSharpEssentials.Entity.Interfaces;

// AfterSave (default) — published after commit, safe for notifications
public sealed class OrderCreatedEvent(Guid orderId) : IDomainEvent
{
    public Guid OrderId { get; } = orderId;
}

// BeforeSave — published before commit, can abort the save on failure
[DomainEventTiming(DomainEventTiming.BeforeSave)]
public sealed class OrderValidationEvent(Guid orderId) : IDomainEvent
{
    public Guid OrderId { get; } = orderId;
}
Raising Events
// In your entity (inherits from EntityBase which implements IDomainEventHolder)
public void UpdatePrice(decimal newPrice)
{
    decimal oldPrice = Price;
    Price = newPrice;
    Raise(new PriceChangedEvent(Id, oldPrice, newPrice));
}

Events are collected entity-by-entity in ChangeTracker order, preserving the list index within each entity.

Outbox Pattern

Register an IDomainEventOutbox for reliable delivery. AfterSave events are routed to the outbox; BeforeSave events are always published directly.

services.AddSingleton<IDomainEventOutbox, EfCoreOutbox>();

3. Slow Query Logging

Register the interceptor to find performance bottlenecks.

using CSharpEssentials.EntityFrameworkCore.Interceptors;

// Default threshold: 1 second
services.AddSlowQueryInterceptor();

// Custom threshold
services.AddSlowQueryInterceptor(TimeSpan.FromMilliseconds(500));

// With configure action
services.AddSlowQueryInterceptor(options =>
    options.Threshold = TimeSpan.FromSeconds(2));

// Register with DbContext
services.AddDbContext<MyDbContext>((sp, options) =>
    options.UseSqlServer(connectionString)
           .AddInterceptors(sp.GetRequiredService<SlowQueryInterceptor>()));

Queries taking longer than the threshold will be logged as Warnings.

Custom Slow Query Handler

Implement ISlowQueryHandler for custom metrics or alerting:

public sealed class PrometheusSlowQueryHandler : ISlowQueryHandler
{
    public void OnSlowQuery(SlowQueryContext context)
    {
        // Push to Prometheus, OpenTelemetry, etc.
        SlowQueryCounter.Inc();
    }
}

services.AddSingleton<ISlowQueryHandler, PrometheusSlowQueryHandler>();

4. Pagination (Offset-based)

Easily paginate any IQueryable.

using CSharpEssentials.EntityFrameworkCore.Pagination;
using CSharpEssentials.EntityFrameworkCore.Pagination.Requests;

var request = new PaginationRequest { PageNumber = 1, PageSize = 10 };

var response = await dbContext.Users
    .PaginateAsync(request, cancellationToken: ct);

var items = response.Data;
var total = response.TotalCount;

5. Cursor Pagination (High Performance)

Use cursor-based pagination for infinite scroll scenarios or large datasets where offset pagination is slow.

using CSharpEssentials.EntityFrameworkCore.Pagination;

var request = new CursorPaginationRequest<DateTimeOffset>
{
    Limit = 20,
    Cursor = lastSeenDate
};

var response = await dbContext.Logs
    .PaginateAsync(
        request,
        cursorSelector: x => x.CreatedAt,
        isAscending: false
    );

var nextCursor = response.NextCursor;

Supports any IComparable<T> cursor type: string, int, Guid, DateTimeOffset, etc.

6. Base DbContext

Inherit from BaseDbContext for automatic logger injection and instance tracking.

using CSharpEssentials.EntityFrameworkCore;

public class MyDbContext : BaseDbContext<MyDbContext>
{
    public MyDbContext(DbContextOptions<MyDbContext> options, IServiceScopeFactory scopeFactory)
        : base(options, scopeFactory)
    {
    }
}

Full Setup Example

var services = new ServiceCollection();

services.AddLogging(b => b.AddConsole());

// Interceptors — one line each
services.AddAuditInterceptor(() => "demo-user");
services.AddSlowQueryInterceptor(TimeSpan.FromMilliseconds(500));
services.AddSingleton<IDomainEventPublisher, MyPublisher>();
services.AddSingleton<DomainEventInterceptor>();

// DbContext with all interceptors
services.AddDbContext<ShopDbContext>((sp, options) =>
    options.UseSqlServer(connectionString)
           .AddInterceptors(
               sp.GetRequiredService<AuditInterceptor>(),
               sp.GetRequiredService<DomainEventInterceptor>(),
               sp.GetRequiredService<SlowQueryInterceptor>()));
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.3 0 5/5/2026
3.0.2 13 5/5/2026
3.0.1 39 5/3/2026
3.0.0 38 5/3/2026
2.1.0 222 11/26/2025
2.0.9 218 9/30/2025
2.0.8 205 9/29/2025
2.0.7 205 9/29/2025
2.0.6 209 9/29/2025
2.0.5 208 9/29/2025
2.0.4 199 9/28/2025
2.0.3 202 9/28/2025
2.0.2 208 9/28/2025
2.0.1 199 9/28/2025
2.0.0 221 9/28/2025
1.0.16 489 2/4/2025
1.0.15 385 1/29/2025
1.0.14 184 12/27/2024
1.0.13 222 12/18/2024
1.0.12 213 12/18/2024
Loading failed