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
<PackageReference Include="DKNet.EfCore.Extensions" Version="9.0.28" />
<PackageVersion Include="DKNet.EfCore.Extensions" Version="9.0.28" />
<PackageReference Include="DKNet.EfCore.Extensions" />
paket add DKNet.EfCore.Extensions --version 9.0.28
#r "nuget: DKNet.EfCore.Extensions, 9.0.28"
#:package DKNet.EfCore.Extensions@9.0.28
#addin nuget:?package=DKNet.EfCore.Extensions&version=9.0.28
#tool nuget:?package=DKNet.EfCore.Extensions&version=9.0.28
DKNet.EfCore.Extensions
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 assembliesAddGlobalModelBuilderRegister<T>()
- Register global query filtersSeedDataAsync<TEntity>()
- Perform structured data seeding
Entity Extensions
GetTableName(Type)
- Get schema-qualified table name for entityGetPrimaryKeyProperty(Type)
- Extract primary key property informationGetPrimaryKeyValue(object)
- Get primary key value from entity instance
Sequence Extensions (SQL Server)
GetNextSequenceValue(string)
- Get next value from database sequenceGetFormattedSequenceValue(string, string)
- Get formatted sequence with prefix/suffix
Snapshot Extensions
CreateSnapshot()
- Create entity state snapshot for change trackingGetChanges(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:
- Included Entities: Classes implementing
IEntity<TKey>
from specified assemblies - Excluded Entities: Classes marked with
[IgnoreEntity]
attribute - Configuration Priority: Explicit configurations override default configurations
- 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.
Related Packages
- DKNet.EfCore.Abstractions - Core abstractions and interfaces
- DKNet.EfCore.Hooks - Entity lifecycle hooks
- DKNet.EfCore.Repos - Repository pattern implementations
- DKNet.EfCore.Events - Domain event handling
Part of the DKNet Framework - A comprehensive .NET framework for building modern, scalable applications.
Product | Versions 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. |
-
net9.0
- DKNet.EfCore.Abstractions (>= 9.0.28)
- DKNet.Fw.Extensions (>= 9.0.28)
- Microsoft.EntityFrameworkCore (>= 9.0.9)
- Microsoft.EntityFrameworkCore.Relational (>= 9.0.9)
- System.ComponentModel.Annotations (>= 5.0.0)
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 |