Syntrony.EntityFrameworkCore.Repositories
1.0.0
dotnet add package Syntrony.EntityFrameworkCore.Repositories --version 1.0.0
NuGet\Install-Package Syntrony.EntityFrameworkCore.Repositories -Version 1.0.0
<PackageReference Include="Syntrony.EntityFrameworkCore.Repositories" Version="1.0.0" />
<PackageVersion Include="Syntrony.EntityFrameworkCore.Repositories" Version="1.0.0" />
<PackageReference Include="Syntrony.EntityFrameworkCore.Repositories" />
paket add Syntrony.EntityFrameworkCore.Repositories --version 1.0.0
#r "nuget: Syntrony.EntityFrameworkCore.Repositories, 1.0.0"
#:package Syntrony.EntityFrameworkCore.Repositories@1.0.0
#addin nuget:?package=Syntrony.EntityFrameworkCore.Repositories&version=1.0.0
#tool nuget:?package=Syntrony.EntityFrameworkCore.Repositories&version=1.0.0
Syntrony.EntityFrameworkCore.Repositories
EF Core implementation of the Syntrony.Repositories
contract: EfCoreRepositoryBase<TDbContext, TEntity, TKey>, automatic registration of the generic
repository, and the IUnitOfWorkParticipant that enlists a DbContext in Syntrony's unit of
work. Replaces ABP's EfCoreRepositoryBase and EfCoreUnitOfWork.
Provider-agnostic by construction: depends only on Microsoft.EntityFrameworkCore.Relational,
never on Npgsql.* or SqlServer.*. The consumer picks the engine in its own AddDbContext call.
Installation
dotnet add package Syntrony.EntityFrameworkCore.Repositories
Usage
The DI container cannot close the leading TDbContext parameter when registering an open
generic, so the consumer declares a thin repository closed over its own DbContext — six lines,
in a project that already references EF Core:
// AppRepository.cs
public sealed class AppRepository<TEntity, TKey>(AppDbContext context)
: EfCoreRepositoryBase<AppDbContext, TEntity, TKey>(context)
where TEntity : class, IEntity<TKey>;
builder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(connectionString));
builder.Services.AddSyntrony(options => options
.AddAssemblyContaining<Program>()
.UseWrapper()
.UseUnitOfWork()
.UseEntityFrameworkCoreRepositories<AppDbContext>(typeof(AppRepository<,>)));
From there, any app service can take IRepository<TEntity, TKey> — or the IRepository<TEntity>
shortcut for Guid-keyed entities — without a SaveChanges call, an explicit transaction, or a
try/catch: the unit of work commits when the action finishes without an exception and rolls back
when it doesn't.
public class UserAppService(IRepository<User> users) : IScopedDependency
{
public async Task<Guid> CreateAsync(CreateUserInput input)
{
var user = await users.InsertAsync(new User(input.Email));
return user.Id;
}
}
Resolving a repository outside a request (jobs)
DbContext and the repository are both scoped. A background job has no ambient request scope, so
it creates one explicitly:
await using var scope = serviceProvider.CreateAsyncScope();
var users = scope.ServiceProvider.GetRequiredService<IRepository<User>>();
Opting out of the health check
UseEntityFrameworkCoreRepositories registers AddDbContextCheck<TDbContext>() by default, so
/health reflects the database actually being reachable instead of responding Healthy with no
checks registered at all. Disable it if the consumer wires its own:
options.UseEntityFrameworkCoreRepositories<AppDbContext>(
typeof(AppRepository<,>),
ef => ef.RegisterHealthCheck = false);
Behaviors that surprise
Three things about this package are correct but not obvious from the API alone:
GetAll()cannot be enumerated after itsDbContext's scope has ended. It's a plainIQueryableover the context'sDbSet; awaiting it later (for instance, after a request finished) throwsObjectDisposedException. This is a property of EF Core, not a bug in this package — materialize what you need (ToListAsync,FirstOrDefaultAsync, ...) before leaving the scope that owns the context.GetAllReadonly()can still return an already-tracked instance.AsNoTracking()disables tracking for new results; if the context already tracks a matching entity, EF Core hands back that tracked instance regardless.- PostgreSQL silently promotes
ReadUncommittedtoReadCommitted. The unit of work defaults toReadCommitted, so this doesn't affect the out-of-the-box behavior, but a consumer that explicitly requestsReadUncommittedexpecting dirty reads on Postgres will not get an error — justReadCommittedsemantics instead.
Checked and not a gotcha: an earlier draft of this package assumed lazy-loading navigation properties silently fail to load under
GetAllReadonly()(AsNoTracking()). The integration suite disproves that against EF Core 8 + Npgsql +Microsoft.EntityFrameworkCore.Proxies: a lazy navigation loads the same way underGetAllReadonly()as it does underGetAll(). If a real consumer entity ever does exhibit empty navigations under a no-tracking query, treat it as a new, different bug to investigate — not an instance of this one.
Soft-delete and audit conventions (
SyntronyDbContext, the global query filter,IgnoreQueryFilters()) are deferred: no entity in the current consumer usesISoftDelete/IAuditedyet. Once that lands, this section grows the filter-related gotchas that come with it (thatIgnoreQueryFilters()disables every filter, and that a required navigation to a soft-deleted entity excludes the parent from the results) — they don't apply to this version because the filter itself doesn't exist yet.
Status
EfCoreRepositoryBase, automatic DI registration (both repository shapes) and the unit-of-work
participant are implemented and tested. Auditing and soft-delete are deferred until a consumer
entity needs them.
| 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 was computed. 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. |
-
net8.0
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.11)
- Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore (>= 8.0.0)
- Syntrony (>= 1.3.0 && < 2.0.0)
- Syntrony.Repositories (>= 1.1.0 && < 2.0.0)
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 |
|---|---|---|
| 1.0.0 | 40 | 10/4/2026 |