A small, explicit repository and Result toolkit for Entity Framework Core applications.
Version 3 provides one primary package reference while keeping the Result pattern independently reusable:
| Package | Purpose |
|---|---|
CD.GenericRepository |
Primary package. Includes repository APIs and a dependency on CD.Results. |
CD.Results |
Transport-independent Result pattern for projects that do not use EF Core. |
CD.Results.AspNetCore |
Optional controller and Minimal API response mappings. |
CD.Generic.Repository |
Compatibility package for users migrating from versions 1.x and 2.x. |
dotnet add package CD.GenericRepository --prereleaseThat single reference makes both namespaces available:
using CD.GenericRepository;
using CD.Results;- .NET 8 with EF Core 8
- .NET 9 with EF Core 9
- .NET 10 with EF Core 10
Create your context normally:
public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
: DbContext(options)
{
public DbSet<User> Users => Set<User>();
}Create an application-specific repository:
public interface IUserRepository : IRepository<User>;
public sealed class UserRepository(AppDbContext context)
: Repository<User, AppDbContext>(context), IUserRepository;Register it with dependency injection:
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Database")));
builder.Services.AddGenericRepositories<AppDbContext>();
builder.Services.AddScoped<IUserRepository, UserRepository>();Use async, cancellation-aware operations and explicit results:
public async Task<Result<User>> GetByIdAsync(
int id,
CancellationToken cancellationToken = default)
{
User? user = await repository.GetAsync(
candidate => candidate.Id == id,
cancellationToken: cancellationToken);
return user is null
? Result<User>.NotFound($"User not found with id: {id}", "user.not_found")
: Result<User>.Success(user);
}For Web APIs, add the optional adapter and let it map error types to HTTP:
dotnet add package CD.Results.AspNetCore --prereleasereturn result.ToActionResult();- Read queries are no-tracking by default. Request tracking explicitly when updating loaded entities.
- Repository changes are persisted only when
IUnitOfWork.SaveChangesAsyncis called. - Missing entities return
nullorfalse; delete operations do not passnullto EF Core. - Every async query accepts and forwards a
CancellationToken. - Projection and ordered paging are executed by the database provider.
ITransactionalUnitOfWorkcommits successful operations and rolls failures back.- Public API contract files make accidental breaking changes fail during CI.
- The 2.x API remains available as obsolete migration members for one major release.
See the v3 migration guide and the sample API.
dotnet restore CD.GenericRepository.sln
dotnet build CD.GenericRepository.sln --configuration Release --no-restore
dotnet test CD.GenericRepository.sln --configuration Release --no-build
dotnet pack CD.GenericRepository.sln --configuration Release --no-buildMIT