DKNet.EfCore.Extensions 9.0.28

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

DKNet.EfCore.Extensions

NuGet NuGet Downloads .NET License

Enhanced Entity Framework Core functionality with automatic entity configuration, global query filters, data seeding, and advanced extension methods. This package streamlines EF Core setup and provides powerful utilities for entity management, pagination, and database operations.

Features

  • Auto Entity Configuration: Automatic discovery and configuration of entities from assemblies
  • Global Query Filters: Centralized query filter management for cross-cutting concerns
  • Data Seeding: Structured data seeding with dependency injection support
  • Default Entity Configuration: Base configuration for common entity patterns (audit, soft delete)
  • Advanced Extensions: Table name resolution, primary key utilities, sequence generation
  • Snapshot Context: Entity state tracking and change detection utilities
  • Navigation Extensions: Enhanced navigation property management
  • Pagination Support: Async enumeration and paging capabilities

Supported Frameworks

  • .NET 9.0+
  • Entity Framework Core 9.0+
  • SQL Server (for sequence features)

Installation

Install via NuGet Package Manager:

dotnet add package DKNet.EfCore.Extensions

Or via Package Manager Console:

Install-Package DKNet.EfCore.Extensions

Quick Start

Auto Entity Configuration

using Microsoft.EntityFrameworkCore;
using DKNet.EfCore.Extensions;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Automatically configure all entities from assemblies
        modelBuilder.UseAutoConfigModel<AppDbContext>(config =>
        {
            config.AddAssembly(typeof(Product).Assembly);
            config.AddAssembly(typeof(Customer).Assembly);
        });
        
        base.OnModelCreating(modelBuilder);
    }
}

// Configure in Startup/Program
services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString)
           .UseAutoConfigModel<AppDbContext>());

Default Entity Configuration

using DKNet.EfCore.Extensions.Configurations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

public class ProductConfiguration : DefaultEntityTypeConfiguration<Product>
{
    public override void Configure(EntityTypeBuilder<Product> builder)
    {
        // Apply default configurations (Id, audit properties, etc.)
        base.Configure(builder);
        
        // Add custom configurations
        builder.Property(p => p.Name)
               .HasMaxLength(255)
               .IsRequired();
               
        builder.Property(p => p.Price)
               .HasPrecision(18, 2);
               
        builder.HasIndex(p => p.Sku)
               .IsUnique();
    }
}

Global Query Filters

using DKNet.EfCore.Extensions.Configurations;

public class SoftDeleteQueryFilter : IGlobalQueryFilterRegister
{
    public void RegisterFilters(ModelBuilder modelBuilder)
    {
        // Apply soft delete filter globally
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(ISoftDeletableEntity).IsAssignableFrom(entityType.ClrType))
            {
                var parameter = Expression.Parameter(entityType.ClrType, "e");
                var property = Expression.Property(parameter, nameof(ISoftDeletableEntity.IsDeleted));
                var condition = Expression.Equal(property, Expression.Constant(false));
                var lambda = Expression.Lambda(condition, parameter);
                
                modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda);
            }
        }
    }
}

// Register in Startup
services.AddGlobalModelBuilderRegister<SoftDeleteQueryFilter>();

Configuration

Data Seeding Configuration

using DKNet.EfCore.Extensions.Configurations;

public class CategorySeedData : IDataSeedingConfiguration<Category>
{
    public async Task SeedAsync(DbContext context, IServiceProvider serviceProvider)
    {
        var repository = serviceProvider.GetRequiredService<ICategoryRepository>();
        
        if (!await repository.AnyAsync())
        {
            var categories = new[]
            {
                new Category("Electronics", "Electronic devices"),
                new Category("Books", "Books and publications"),
                new Category("Clothing", "Apparel and accessories")
            };
            
            await repository.AddRangeAsync(categories);
            await context.SaveChangesAsync();
        }
    }
}

// Apply seeding
await context.SeedDataAsync<Category>();

Entity Auto-Registration Options

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(connectionString)
           .UseAutoConfigModel<AppDbContext>(config =>
           {
               // Add specific assemblies
               config.AddAssembly(typeof(Product).Assembly);
               
               // Exclude specific entity types
               config.ExcludeEntity<TemporaryEntity>();
               
               // Configure naming conventions
               config.UseSnakeCaseNaming();
               config.UsePluralTableNames();
           });
});

API Reference

Core Extensions

  • UseAutoConfigModel<TContext>() - Auto-configure entities from assemblies
  • AddGlobalModelBuilderRegister<T>() - Register global query filters
  • SeedDataAsync<TEntity>() - Perform structured data seeding

Entity Extensions

  • GetTableName(Type) - Get schema-qualified table name for entity
  • GetPrimaryKeyProperty(Type) - Extract primary key property information
  • GetPrimaryKeyValue(object) - Get primary key value from entity instance

Sequence Extensions (SQL Server)

  • GetNextSequenceValue(string) - Get next value from database sequence
  • GetFormattedSequenceValue(string, string) - Get formatted sequence with prefix/suffix

Snapshot Extensions

  • CreateSnapshot() - Create entity state snapshot for change tracking
  • GetChanges(SnapshotContext) - Detect changes between snapshots

Advanced Usage

Custom Entity Configuration with Sequences

public class InvoiceConfiguration : DefaultEntityTypeConfiguration<Invoice>
{
    public override void Configure(EntityTypeBuilder<Invoice> builder)
    {
        base.Configure(builder);
        
        // Configure SQL sequence for invoice numbers
        builder.Property(i => i.InvoiceNumber)
               .HasDefaultValueSql("NEXT VALUE FOR invoice_number_seq");
               
        // Configure custom table and schema
        builder.ToTable("Invoices", "billing");
        
        // Configure relationships
        builder.HasMany(i => i.LineItems)
               .WithOne(li => li.Invoice)
               .HasForeignKey(li => li.InvoiceId)
               .OnDelete(DeleteBehavior.Cascade);
    }
}

Advanced Query Filter with User Context

public class TenantQueryFilter : IGlobalQueryFilterRegister
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    
    public TenantQueryFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    
    public void RegisterFilters(ModelBuilder modelBuilder)
    {
        var tenantId = GetCurrentTenantId();
        
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(ITenantEntity).IsAssignableFrom(entityType.ClrType))
            {
                var parameter = Expression.Parameter(entityType.ClrType, "e");
                var property = Expression.Property(parameter, nameof(ITenantEntity.TenantId));
                var condition = Expression.Equal(property, Expression.Constant(tenantId));
                var lambda = Expression.Lambda(condition, parameter);
                
                modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda);
            }
        }
    }
    
    private Guid GetCurrentTenantId()
    {
        // Extract tenant ID from HTTP context, claims, etc.
        return _httpContextAccessor.HttpContext?.User
            ?.FindFirst("tenant_id")?.Value 
            ?? Guid.Empty;
    }
}

Bulk Data Seeding with Dependencies

public class ProductSeedData : IDataSeedingConfiguration<Product>
{
    public async Task SeedAsync(DbContext context, IServiceProvider serviceProvider)
    {
        var categoryRepo = serviceProvider.GetRequiredService<ICategoryRepository>();
        var logger = serviceProvider.GetRequiredService<ILogger<ProductSeedData>>();
        
        try
        {
            if (!await context.Set<Product>().AnyAsync())
            {
                var categories = await categoryRepo.GetAllAsync();
                var electronics = categories.First(c => c.Name == "Electronics");
                
                var products = new[]
                {
                    new Product("Laptop", 1299.99m, electronics.Id, "admin"),
                    new Product("Mouse", 29.99m, electronics.Id, "admin"),
                    new Product("Keyboard", 89.99m, electronics.Id, "admin")
                };
                
                context.Set<Product>().AddRange(products);
                await context.SaveChangesAsync();
                
                logger.LogInformation("Seeded {Count} products", products.Length);
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Failed to seed product data");
            throw;
        }
    }
}

Entity Discovery Rules

The auto-configuration system follows these rules:

  1. Included Entities: Classes implementing IEntity<TKey> from specified assemblies
  2. Excluded Entities: Classes marked with [IgnoreEntity] attribute
  3. Configuration Priority: Explicit configurations override default configurations
  4. Naming Conventions: Configurable table and column naming strategies

Performance Considerations

  • Assembly Scanning: Performed once during startup, cached for application lifetime
  • Global Filters: Applied at query compilation time, minimal runtime overhead
  • Sequence Operations: Direct SQL execution for optimal performance
  • Snapshot Context: Lightweight change tracking, use for critical audit scenarios

Thread Safety

  • Configuration registration is thread-safe during startup
  • Runtime query operations are thread-safe following EF Core patterns
  • Sequence generation is atomic at database level
  • Global filter state is immutable after configuration

Contributing

See the main CONTRIBUTING.md for guidelines on how to contribute to this project.

License

This project is licensed under the MIT License.


Part of the DKNet Framework - A comprehensive .NET framework for building modern, scalable applications.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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 (3)

Showing the top 3 NuGet packages that depend on DKNet.EfCore.Extensions:

Package Downloads
DKNet.EfCore.Hooks

Package Description

DKNet.EfCore.Repos

Package Description

DKNet.EfCore.DataAuthorization

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
9.0.28 0 9/17/2025
9.0.27 0 9/17/2025
9.0.26 36 9/16/2025
9.0.25 31 9/15/2025
9.0.24 28 9/15/2025
9.0.23 118 9/6/2025
9.0.22 167 9/3/2025
9.0.21 139 9/1/2025
9.0.20 166 7/15/2025
9.0.19 165 7/14/2025
9.0.18 162 7/14/2025
9.0.17 156 7/14/2025
9.0.16 138 7/11/2025
9.0.15 150 7/11/2025
9.0.14 139 7/11/2025
9.0.13 146 7/11/2025
9.0.12 162 7/8/2025
9.0.11 156 7/8/2025
9.0.10 157 7/7/2025
9.0.9 167 7/2/2025
9.0.8 158 7/2/2025
9.0.7 167 7/1/2025
9.0.6 161 6/30/2025
9.0.5 166 6/24/2025
9.0.4 166 6/24/2025
9.0.3 170 6/23/2025
9.0.2 166 6/23/2025
9.0.1 167 6/23/2025