Sumapap.Persistence.EfCore
1.0.1
dotnet add package Sumapap.Persistence.EfCore --version 1.0.1
NuGet\Install-Package Sumapap.Persistence.EfCore -Version 1.0.1
<PackageReference Include="Sumapap.Persistence.EfCore" Version="1.0.1" />
<PackageVersion Include="Sumapap.Persistence.EfCore" Version="1.0.1" />
<PackageReference Include="Sumapap.Persistence.EfCore" />
paket add Sumapap.Persistence.EfCore --version 1.0.1
#r "nuget: Sumapap.Persistence.EfCore, 1.0.1"
#:package Sumapap.Persistence.EfCore@1.0.1
#addin nuget:?package=Sumapap.Persistence.EfCore&version=1.0.1
#tool nuget:?package=Sumapap.Persistence.EfCore&version=1.0.1
Sumapap.Persistence.EFCore
💡 Overview
Sumapap.Persistence.EFCore provides concrete, EF Core-based implementations of the persistence abstractions defined
in Sumapap.Persistence. It ships generic repositories, a Unit of Work implementation and a specification evaluator
that integrate with Entity Framework Core to let you focus on domain logic rather than plumbing.
Included implementations:
ReadRepository<TEntity, TContext>— EF Core read-side repository (AsNoTracking by default, streaming, queries, specs).WriteRepository<TEntity, TContext>— EF Core write-side repository (Add/Update/Delete + Save/SaveAsync).ReadWriteRepository<TEntity, TContext>— composition of read and write behaviors exposing the full CRUD surface.UnitOfWork<TContext>— manages a DbContext instance and (optional) explicit transactions with Begin/Commit/Rollback support.SpecificationEvaluator— appliesISpecification<T>includes, filters and query options toIQueryable.DependencyInjectionhelpers — convenient registration for generic repositories and unit-of-work.
✨ Why Sumapap.Persistence.EFCore?
- Reuses the small, testable persistence contracts from
Sumapap.Persistencewhile leveraging EF Core features (tracking, change detection, transactions). - Provides sensible defaults for read operations (
AsNoTracking) and streaming large result sets. - Centralizes specification evaluation so query composition is consistent across repositories.
- Easy DI integration via extension methods; works well in layered applications.
🚀 Quick start
- Add the package to your project (when published on NuGet):
dotnet add package Sumapap.Persistence.EFCore
- Create your EF Core DbContext and entities (entities implement
IEntityorIEntity<TKey>):
public class AppDbContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}
}
public class Order : IEntity<Guid>
{
public Guid Id { get; set; }
public Guid CustomerId { get; set; }
}
- Register EF Core persistence in DI (recommended):
services.AddEfCorePersistence<AppDbContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("Default")));
This registers the generic repository types and the IUnitOfWork<TContext> implementation and also registers your DbContext.
- Use the repositories / unit of work in application services:
public class OrderService
{
private readonly IUnitOfWork<AppDbContext> _uow;
public OrderService(IUnitOfWork<AppDbContext> uow) => _uow = uow;
public async Task CreateOrderAsync(Order order)
{
var repo = _uow.GetRepository<Order>();
repo.Add(order);
await _uow.SaveChangesAsync();
}
}
🛠️ Features & Usage Details
ReadRepository
- Uses
DbSet<TEntity>and EF Core's query APIs. - Default read operations use
AsNoTracking()for improved read performance and to avoid accidental state changes. - Supports synchronous and asynchronous operations, streaming (
IAsyncEnumerable<T>), and specification-based queries viaISpecification<T>. ApplySpecificationdelegates include/filter/paging logic toSpecificationEvaluator.
WriteRepository
- Implements add/update/delete operations using
DbSet.Add/Update/Removeand their async variants where appropriate. - Save operations call
_context.SaveChanges()/_context.SaveChangesAsync(); changes are persisted only when save is invoked. - Delete by id operations use
Find/FindAsyncto materialize entity before removal.
ReadWriteRepository
- Thin facade that composes
ReadRepositoryandWriteRepositoryto provide a single read/write surface for convenience.
UnitOfWork
- Wraps a
DbContextinstance and maintains an internal cache of created repository instances so all repo instances in a UoW share the same context. - Supports:
SaveChangesAsync()for committing changes (EF Core creates implicit transactions by default).BeginTransactionAsync/CommitTransactionAsync/RollbackTransactionAsyncfor explicit transaction control.ExecuteAsync(Func<CancellationToken, Task>)that runs the provided operation inside an explicit transaction and commits/rolls back appropriately.
- Disposal: The UoW implements both
IDisposableandIAsyncDisposable. It ensures explicit transactions are rolled back/disposed if still active on dispose. It does not dispose the underlying DbContext (DI typically manages that lifetime).
SpecificationEvaluator
- Applies the
ISpecification<T>to anIQueryable<T>by:- Applying the Criteria filter expression if present.
- Optionally skipping includes/paging when only criteria evaluation is required (useful for Count/Exists optimizations).
- Applying Includes (string-based navigation paths using EF Core
Includeoverload that accepts string). - Executing optional
IQueryquery options (paging/sorting) via the query execution helpers.
DependencyInjection
AddEfCorePersistence()registers the open generic types:IReadWriteRepository<,>→ReadWriteRepository<,>IReadRepository<,>→ReadRepository<,>IWriteRepository<,>→WriteRepository<,>IUnitOfWork<>→UnitOfWork<>
AddEfCorePersistence<TContext>(Action<DbContextOptionsBuilder>)also registers the specifiedDbContextwith the provided configuration.
⚠️ Notes & Best Practices
- Transaction boundaries — prefer dispatching domain events or notifying external systems only after
SaveChangesAsynccompletes successfully. - Handler lifetimes — repositories and DbContext are typically registered as Scoped. Do not hold DbContext across threads or beyond its scope.
- Explicit transactions — use
BeginTransactionAsynconly when you need to coordinate multipleSaveChangescalls or cross-cutting transactional work. - Performance —
SpecificationEvaluatoruses string-based includes for simplicity; prefer expression-based includes in custom repositories when you need compile-time safety. - Large result sets — use
StreamAllAsync/StreamWhereAsyncto process results without loading all rows into memory.
✅ Example
// Register in Program.cs
services.AddEfCorePersistence<AppDbContext>(opts => opts.UseSqlServer(connString));
// Application service
public class OrdersAppService
{
private readonly IUnitOfWork<AppDbContext> _uow;
private readonly IDomainEventDispatcher _dispatcher; // if using domain events
public OrdersAppService(IUnitOfWork<AppDbContext> uow, IDomainEventDispatcher dispatcher)
{
_uow = uow;
_dispatcher = dispatcher;
}
public async Task PlaceOrderAsync(Order order, CancellationToken ct)
{
var repo = _uow.GetRepository<Order>();
repo.Add(order);
await _uow.SaveChangesAsync(ct);
// dispatch domain events after successful commit
if (order is DomainEntity domainEntity)
{
var events = domainEntity.ConsumeEvents();
await _dispatcher.DispatchAsync(events, ct);
}
}
}
💪 Contributions
Contributions are welcome! If you encounter a bug, have a suggestion, or want to contribute code, please follow these steps:
- Check the GitHub Issues.
- If not reported, open a new issue describing the bug or feature request.
- For code contributions:
- Fork the repository.
- Create your feature branch:
git checkout -b feature/YourAmazingFeature. - Commit changes and include tests for new/modified functionality.
- Open a pull request against
main.
⭐ License
Distributed under the MIT License. See the LICENSE file in the repository for more information.
🚩 Contact
GitHub @muhirwanto-dev
Project Url https://github.com/muhirwanto-dev/sumapap/tree/main/source/Sumapap.Persistence.EfCore
| Product | Versions 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. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.5)
- Sumapap.Persistence (>= 1.0.1)
- Sumapap.Queries.Execution.EfCore (>= 1.4.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.