DotEmilu.EntityFrameworkCore 10.0.0

Prefix Reserved
dotnet add package DotEmilu.EntityFrameworkCore --version 10.0.0
                    
NuGet\Install-Package DotEmilu.EntityFrameworkCore -Version 10.0.0
                    
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="DotEmilu.EntityFrameworkCore" Version="10.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DotEmilu.EntityFrameworkCore" Version="10.0.0" />
                    
Directory.Packages.props
<PackageReference Include="DotEmilu.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 DotEmilu.EntityFrameworkCore --version 10.0.0
                    
#r "nuget: DotEmilu.EntityFrameworkCore, 10.0.0"
                    
#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 DotEmilu.EntityFrameworkCore@10.0.0
                    
#: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=DotEmilu.EntityFrameworkCore&version=10.0.0
                    
Install as a Cake Addin
#tool nuget:?package=DotEmilu.EntityFrameworkCore&version=10.0.0
                    
Install as a Cake Tool

DotEmilu.EntityFrameworkCore

NuGet License: MIT

Entity Framework Core utilities for DotEmilu — auditable entity interceptors, soft-delete interceptor, base entity configurations with TPC/TPH/TPT mapping strategies, pagination, and CQRS-ready patterns.

Install

dotnet add package DotEmilu.EntityFrameworkCore

This transitively installs DotEmilu.Abstractions.

What's included

Interceptors

Type Purpose
AuditableEntityInterceptor<TUserKey> Automatically sets Created, CreatedBy, LastModified, LastModifiedBy, Deleted, DeletedBy on SaveChanges using IContextUser<TUserKey> and TimeProvider
SoftDeleteInterceptor Converts EntityState.Deleted to EntityState.Unchanged + IsDeleted = true for all IBaseEntity implementations

Entity configurations

Type Purpose
BaseEntityConfiguration<TEntity, TKey> Configures primary key, ValueGeneratedOnAdd, IsDeleted column, optional RowVersion, and mapping strategy
BaseAuditableEntityConfiguration<TEntity, TUserKey> Configures all audit columns (Created, CreatedBy, etc.), IsDeleted, and mapping strategy

Mapping strategies

Enum value Strategy
MappingStrategy.Tpc Table-per-concrete-type (default)
MappingStrategy.Tph Table-per-hierarchy
MappingStrategy.Tpt Table-per-type

Extension methods

EntityTypeBuilder extensions:

Method Purpose
builder.UseIsDeleted(useShort, useIndex, useQueryFilter, order) Configures IsDeleted column — optional short (0/1) conversion, global query filter, index
builder.ApplyMappingStrategy(strategy) Applies TPC/TPH/TPT to the entity

PropertyBuilder extensions:

Method Purpose
property.HasShortConversion() Converts bool to short (0/1) in the database
property.HasFormattedComment(format, includeTitle) Auto-generates SQL column comments from enum values and [Description] attributes

ModelBuilder extensions:

Method Purpose
modelBuilder.ApplyBaseEntityConfiguration<TKey>(strategy, enableRowVersion) Applies BaseEntityConfiguration to all IBaseEntity<TKey> types in the model
modelBuilder.ApplyBaseEntityConfiguration(assembly, keyTypeConfigurations?) Assembly-scanning overload with per-key-type customization
modelBuilder.ApplyBaseAuditableEntityConfiguration<TUserKey>(strategy) Applies BaseAuditableEntityConfiguration to all IBaseAuditableEntity<TUserKey> types
modelBuilder.ApplyBaseAuditableEntityConfiguration(assembly, userKeyConfigurations?) Assembly-scanning overload

IQueryable extensions:

Method Purpose
source.AsPaginatedListAsync(pageNumber, pageSize, ct) Converts an IQueryable<T> to PaginatedList<T> using EF Core's CountAsync/ToListAsync

Contracts

Type Purpose
IUnitOfWork Exposes Database and SaveChangesAsync() for unit-of-work pattern

DI registration

Method Purpose
services.AddSoftDeleteInterceptor() Registers SoftDeleteInterceptor as scoped ISaveChangesInterceptor
services.AddAuditableEntityInterceptor<TContextUser, TUserKey>() Registers a specific AuditableEntityInterceptor<TUserKey> + IContextUser + TimeProvider
services.AddAuditableEntityInterceptors(assembly) Scans assembly for IContextUser<> implementations and registers interceptors for each user key type

Auditable entities

// Define an auditable entity
public class Invoice : BaseAuditableEntity<int, Guid>
{
    public string Number { get; set; } = default!;
    public decimal Amount { get; set; }
    public DateOnly Date { get; set; }
}

// Implement IContextUser<Guid> for audit tracking
public class CurrentUser(IHttpContextAccessor accessor) : IContextUser<Guid>
{
    public Guid Id => Guid.Parse(accessor.HttpContext!.User.FindFirstValue(ClaimTypes.NameIdentifier)!);
}

// Register interceptors
services
    .AddSoftDeleteInterceptor()
    .AddAuditableEntityInterceptors(Assembly.GetExecutingAssembly());

DbContext configuration

public class InvoiceDbContext(DbContextOptions<InvoiceDbContext> options) : DbContext(options)
{
    public DbSet<Invoice> Invoices => Set<Invoice>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Auto-configure audit columns for all IBaseAuditableEntity<Guid> entities
        modelBuilder.ApplyBaseAuditableEntityConfiguration<Guid>();

        // Auto-configure base entity columns from assembly
        modelBuilder.ApplyBaseEntityConfiguration(typeof(Invoice).Assembly);

        // Apply custom IEntityTypeConfiguration<T> from assembly
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(InvoiceDbContext).Assembly);
    }
}

Soft delete with IsDeleted column options

public class SongConfiguration : IEntityTypeConfiguration<Song>
{
    public void Configure(EntityTypeBuilder<Song> builder)
    {
        // Store IsDeleted as short (0/1) instead of bool, with index and query filter
        builder.UseIsDeleted(useShort: true, useIndex: true, useQueryFilter: true, order: 1);

        // Apply TPT mapping strategy
        builder.ApplyMappingStrategy(MappingStrategy.Tpt);
    }
}

Enum column comments

// Automatically generate SQL comments from enum values
builder.Property(s => s.SongType)
    .HasFormattedComment("{0} = {1}")     // "0 = Rock, 1 = Pop, 2 = Jazz"
    .IsRequired();

// Include [Description] attributes
builder.Property(s => s.Status)
    .HasFormattedComment("{0} = {2}", includeTitle: true);  // "Order Status: 0 = Pending Order, 1 = Completed"

Pagination

var result = await db.Invoices
    .OrderBy(i => i.Id)
    .AsPaginatedListAsync(pageNumber: 1, pageSize: 10, cancellationToken);

// result.Items           → IReadOnlyCollection<Invoice>
// result.TotalCount      → total records
// result.TotalPages      → computed from count / pageSize
// result.PageNumber       → current page
// result.HasPreviousPage → bool
// result.HasNextPage     → bool

CQRS pattern

Separate read and write concerns using interface segregation:

// Commands interface (tracked, read-write)
public interface IInvoiceCommands : IInvoiceEntities, IUnitOfWork;

// Queries interface (no-tracking, read-only)
public interface IInvoiceQueries : IInvoiceEntities;

// Shared entity sets
public interface IInvoiceEntities
{
    DbSet<Invoice> Invoices { get; }
}

Additional documentation

Part of the DotEmilu ecosystem

Package Description
DotEmilu.Abstractions Core interfaces and base classes
DotEmilu Handler pipeline with FluentValidation
DotEmilu.AspNetCore ASP.NET Core Minimal API integration
DotEmilu.EntityFrameworkCore (this) EF Core interceptors and configurations

Feedback

File bugs, feature requests, or questions on GitHub Issues.

Full documentation & source

Product 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. 
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
10.0.0 97 4/3/2026
2.0.2 165 10/19/2025
2.0.1 171 8/24/2025
2.0.0 200 3/29/2025
1.0.3 183 2/18/2025
1.0.2 174 2/18/2025
1.0.1 191 2/5/2025
1.0.0 204 1/28/2025