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
                    
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="Syntrony.EntityFrameworkCore.Repositories" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Syntrony.EntityFrameworkCore.Repositories" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Syntrony.EntityFrameworkCore.Repositories" />
                    
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 Syntrony.EntityFrameworkCore.Repositories --version 1.0.0
                    
#r "nuget: Syntrony.EntityFrameworkCore.Repositories, 1.0.0"
                    
#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 Syntrony.EntityFrameworkCore.Repositories@1.0.0
                    
#: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=Syntrony.EntityFrameworkCore.Repositories&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Syntrony.EntityFrameworkCore.Repositories&version=1.0.0
                    
Install as a Cake Tool

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:

  1. GetAll() cannot be enumerated after its DbContext's scope has ended. It's a plain IQueryable over the context's DbSet; awaiting it later (for instance, after a request finished) throws ObjectDisposedException. 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.
  2. 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.
  3. PostgreSQL silently promotes ReadUncommitted to ReadCommitted. The unit of work defaults to ReadCommitted, so this doesn't affect the out-of-the-box behavior, but a consumer that explicitly requests ReadUncommitted expecting dirty reads on Postgres will not get an error — just ReadCommitted semantics 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 under GetAllReadonly() as it does under GetAll(). 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 uses ISoftDelete/IAudited yet. Once that lands, this section grows the filter-related gotchas that come with it (that IgnoreQueryFilters() 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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