Phymnary.SugarPot.AspNetCore.EntityFrameworkCore
1.2.2
dotnet add package Phymnary.SugarPot.AspNetCore.EntityFrameworkCore --version 1.2.2
NuGet\Install-Package Phymnary.SugarPot.AspNetCore.EntityFrameworkCore -Version 1.2.2
<PackageReference Include="Phymnary.SugarPot.AspNetCore.EntityFrameworkCore" Version="1.2.2" />
<PackageVersion Include="Phymnary.SugarPot.AspNetCore.EntityFrameworkCore" Version="1.2.2" />
<PackageReference Include="Phymnary.SugarPot.AspNetCore.EntityFrameworkCore" />
paket add Phymnary.SugarPot.AspNetCore.EntityFrameworkCore --version 1.2.2
#r "nuget: Phymnary.SugarPot.AspNetCore.EntityFrameworkCore, 1.2.2"
#:package Phymnary.SugarPot.AspNetCore.EntityFrameworkCore@1.2.2
#addin nuget:?package=Phymnary.SugarPot.AspNetCore.EntityFrameworkCore&version=1.2.2
#tool nuget:?package=Phymnary.SugarPot.AspNetCore.EntityFrameworkCore&version=1.2.2
Phymnary.SugarPot.AspNetCore.EntityFrameworkCore
Entity Framework Core infrastructure for SugarPot applications.
This package provides:
- Generic EF repositories
- SaveChanges interceptors for auditing, soft delete, and tenant assignment
- ModelBuilder helpers for table naming and global query filters
- Transaction and resilient execution helpers
What Is Included
Repositories
EfRepository<TDbContext, TEntity>EfRepository<TDbContext, TEntity, TKey>- Query/update customization via
IRepositoryOptions<TEntity>:EntityQueryOptions<TEntity>EntityUpdateOptions<TEntity>
Interceptors
OnAttachedInterceptor(always registered byAddEfCoreServices)SoftDeleteInterceptor(opt-in)SetTenantOnSavingInterceptor(opt-in)AuditOnSavingInterceptor(enabled through property-change audit registration)
Helpers
ModelBuilderHelperandBuildEntity(...)IDbFunctionProviderimplementation (DbFunctionProvider<TDbContext>)IQueryTransactionwrapper (WrappedDbContextTransaction)
Target Frameworks And EF Core Versioning
This project targets:
- net8.0
- net9.0
- net10.0
EF Core package version behavior in this project:
- For net10.0-compatible targets:
Microsoft.EntityFrameworkCoreandMicrosoft.EntityFrameworkCore.Relationaluse[10.0.0,) - Otherwise: the same packages use
[8.0.0,)
Installation
dotnet add package Phymnary.SugarPot.AspNetCore.EntityFrameworkCore
Quick Start
1. Register SugarPot EF services
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Phymnary.SugarPot.AspNetCore.Extensions;
services.AddEfCoreServices<AppDbContext>(cfg =>
{
cfg.AddSoftDelete();
cfg.AddMultiTenancy();
// Enables AuditOnSavingInterceptor and property-change tracking
cfg.AddPropertyChangeAudit<AppDbContext, PropertyChangeAudit>(audit => new PropertyChangeAudit
{
EntityName = audit.EntityName,
PropertyName = audit.PropertyName,
TypeName = audit.TypeName,
EntityId = audit.EntityId,
OldValue = audit.OldValue,
NewValue = audit.NewValue,
ModifiedById = audit.ModifiedById,
ModifiedAt = audit.ModifiedAt,
IsDeleted = audit.IsDeleted,
});
});
services.AddDbContext<AppDbContext>((sp, options) =>
{
options.UseSqlServer(connectionString);
// Add all registered EF interceptors
options.AddInterceptors(sp.GetServices<IInterceptor>());
});
2. Inherit the repository base
using Phymnary.SugarPot.AspNetCore.Entities;
using Phymnary.SugarPot.AspNetCore.Repositories;
public sealed class UserRepository(
AppDbContext dbContext,
IRepositoryOptions<User> options,
EfRepositoryAddons addons
) : EfRepository<AppDbContext, User, Guid>(dbContext, options, addons)
{
}
Common methods:
InsertAsyncUpsertAsyncUpdateAsyncFindAsyncQueryAsyncAnyAsyncCountAsyncAdvanceQuery(...)Delete(...)GetAsync(id)for keyed repositories
Repository Options
You can centralize entity behavior with IRepositoryOptions<TEntity>.
using Phymnary.SugarPot.AspNetCore.Repositories;
public sealed class UserRepositoryOptions : EfRepositoryOptions<User>
{
public UserRepositoryOptions()
{
QueryOptions = new EntityQueryOptions<User>
{
DefaultIncludeQuery = q => q,
IncludeDetailsQuery = q => q
.IncludeIn(u => u.Profile)
};
UpdateOptions = new EntityUpdateOptions<User>
{
Update = (input, existing) =>
{
existing.Name = input.Name;
existing.Email = input.Email;
},
};
// Optional domain validator
Validator = null;
}
}
Notes:
UpsertAsyncrequiresUpdateOptions.Update; otherwise it throws.Delete(...)first executesUpdateOptions.OnDeletewhen provided.- If
OnDeletereturnstrue, default delete logic is skipped.
Advanced Query API
AdvanceQuery(...) supports ordering, paging, projection, and pagination metadata.
var page = await repository
.AdvanceQuery(q => q.Where(x => x.IsActive))
.OrderByDescending(x => x.CreatedAt)
.Pick(perPage: 20, pageIndex: 1)
.PaginateAsync(ct);
PaginateAsync returns:
Count: total item count for the base filtered queryItems: pagedIAsyncEnumerable<T>
ModelBuilder Helper
Use ModelBuilderHelper to keep entity mapping consistent.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var helper = new ModelBuilderHelper(modelBuilder)
{
TenantIdAccessor = () => _currentTenant.Id!.Value,
};
helper
.BuildEntity<User>(schema: "app")
.BuildEntity<Order>(schema: "app");
}
Behavior:
- Table name defaults to CLR type name
- Applies soft-delete filter for entities implementing
ISoftDelete - Applies tenant filter for entities implementing
IMultiTenant- On net10.0+, tenant accessor is required for multi-tenant entities
Runtime Dependencies
When enabling features, make sure these services are available in DI from your application/domain layer:
ICurrentUserIRunAtIAbortedTokenICurrentTenant(required when multi-tenancy is enabled)
Notes
OnAttachedInterceptoris always added byAddEfCoreServices.AuditOnSavingInterceptoris registered whenAddPropertyChangeAudit(...)is configured.ConfigureAuditing(...)currently stores internal metadata used by this package.
License
See the repository root for license details.
| Product | Versions 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. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.0)
- Phymnary.SugarPot.AspNetCore.Domain (>= 1.2.2)
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.0)
- Phymnary.SugarPot.AspNetCore.Domain (>= 1.2.2)
-
net9.0
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.0)
- Phymnary.SugarPot.AspNetCore.Domain (>= 1.2.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.