EFRadix.Core.Postgres
1.0.1
See the version list below for details.
dotnet add package EFRadix.Core.Postgres --version 1.0.1
NuGet\Install-Package EFRadix.Core.Postgres -Version 1.0.1
<PackageReference Include="EFRadix.Core.Postgres" Version="1.0.1" />
<PackageVersion Include="EFRadix.Core.Postgres" Version="1.0.1" />
<PackageReference Include="EFRadix.Core.Postgres" />
paket add EFRadix.Core.Postgres --version 1.0.1
#r "nuget: EFRadix.Core.Postgres, 1.0.1"
#:package EFRadix.Core.Postgres@1.0.1
#addin nuget:?package=EFRadix.Core.Postgres&version=1.0.1
#tool nuget:?package=EFRadix.Core.Postgres&version=1.0.1
EFRadix.Core.Postgres
A PostgreSQL data access SDK for .NET 8 built on top of Entity Framework Core and Npgsql. Provides a generic repository pattern, automatic CRUD operations, and a Roslyn source generator that emits typed repository context classes from your DbContext at compile time — zero boilerplate, full IntelliSense.
Table of Contents
- Installation
- Quick Start
- Core Concepts
- Source Generator
- Registration
- Entity Configuration
- Advanced Usage
- Design Notes
Installation
dotnet add package EFRadix.Core.Postgres
Quick Start
1. Define your entities
using EFRadix.Core.Postgres.Entities;
public class Student : BaseEntity
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
2. Define your DbContext
using EFRadix.Core.Postgres.Contexts;
using Microsoft.EntityFrameworkCore;
public class AppDbContext(DbContextOptions<AppDbContext> options)
: BaseNpgsqlDbContext<AppDbContext>(options)
{
public DbSet<Student> Students { get; set; }
}
3. Register in DI
// Program.cs
builder.Services.AddEFRadixNpgsqlDataContext<AppDbContext, AppRepositoryContext>(
builder.Configuration);
4. Inject and use
public class StudentService(IAppRepositoryContext db)
{
public Task<Student?> GetAsync(string id) =>
db.StudentRepository.GetByIdAsync(id);
public Task CreateAsync(Student student) =>
db.StudentRepository.AddAsync(student);
}
IAppRepositoryContextandAppRepositoryContextare generated at compile time by the EFRadix source generator from yourDbSetproperties.
Core Concepts
BaseEntity
All entities must inherit from BaseEntity:
public abstract class BaseEntity
{
public string Id { get; set; } = Guid.NewGuid().ToString("N");
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
Id— a GUID string, auto-generated on construction.CreatedAt— UTC timestamp, set on construction.
Extend with additional audit fields (UpdatedAt, CreatedBy, etc.) as needed.
IBaseRepository<T>
The generic CRUD contract available for every entity:
| Method | Description |
|---|---|
GetQueryable() |
Returns a no-tracking IQueryable<T> for composing custom LINQ queries |
GetByIdAsync(id) |
Fetches a single entity by primary key; returns null if not found |
AddAsync(entity) |
Inserts and immediately saves |
AddRangeAsync(entities) |
Bulk insert and immediately saves |
UpdateAsync(entity) |
Updates and immediately saves |
RemoveAsync(entity) |
Deletes and immediately saves |
RemoveRangeAsync(entities) |
Bulk delete and immediately saves |
SaveChangesAsync() |
Explicitly flushes all pending changes on the context |
All write operations call SaveChangesAsync internally. Use the explicit SaveChangesAsync() when batching multiple tracked changes manually.
IRepositoryContext
The entry point for all repository access:
public interface IRepositoryContext
{
IBaseRepository<T> Repository<T>() where T : BaseEntity;
}
The source generator extends this with named typed properties, giving you:
public interface IAppRepositoryContext : IRepositoryContext
{
IBaseRepository<Student> StudentRepository { get; }
IBaseRepository<Tenant> TenantRepository { get; }
}
Inject IAppRepositoryContext (the generated interface) rather than IRepositoryContext to get typed property access and full IntelliSense.
BaseNpgsqlDbContext<T>
The base class for your DbContext. It handles two things automatically:
- Npgsql switches — configures
EnableLegacyTimestampBehaviorandDisableDateTimeInfinityConversionsbased onNpgsqlDataOptions. - Entity configuration discovery — calls
modelBuilder.ApplyConfigurationsFromAssembly(...)so allIEntityTypeConfiguration<T>implementations in your assembly are applied without manual registration.
public class AppDbContext(DbContextOptions<AppDbContext> options)
: BaseNpgsqlDbContext<AppDbContext>(options)
{
public DbSet<Student> Students { get; set; }
public DbSet<Tenant> Tenants { get; set; }
}
Source Generator
EFRadix includes a Roslyn incremental source generator that runs at compile time. It scans your DbContext for DbSet<T> properties and emits:
I{Name}RepositoryContext— a typed interface extendingIRepositoryContextwith a named property per entity.{Name}RepositoryContext— a partial class implementing the interface, with each property delegating toRepository<T>().
Example — given AppDbContext with DbSet<Student> and DbSet<Tenant>, the generator produces:
// I AppRepositoryContext.g.cs
public interface IAppRepositoryContext : IRepositoryContext
{
IBaseRepository<Student> StudentRepository { get; }
IBaseRepository<Tenant> TenantRepository { get; }
}
// AppRepositoryContext.g.cs
public partial class AppRepositoryContext
: RepositoryContext<AppDbContext>, IAppRepositoryContext
{
public AppRepositoryContext(AppDbContext context) : base(context) { }
public IBaseRepository<Student> StudentRepository => Repository<Student>();
public IBaseRepository<Tenant> TenantRepository => Repository<Tenant>();
}
The generated files appear under Analyzers in your project tree. No additional attributes or configuration are required — the generator detects any class inheriting from BaseNpgsqlDbContext<T> automatically.
Registration
AddEFRadixNpgsqlDataContext
Register your DbContext and generated repository context in one call:
builder.Services.AddEFRadixNpgsqlDataContext<AppDbContext, AppRepositoryContext>(
builder.Configuration);
With options:
builder.Services.AddEFRadixNpgsqlDataContext<AppDbContext, AppRepositoryContext>(
builder.Configuration,
options =>
{
options.ConnectionStringName = "DbConnection";
options.UseJsonNet = true;
});
This registers:
AppDbContextas a scopedDbContextbacked by anNpgsqlDataSource.IRepositoryContext→AppRepositoryContext(scoped).- The
BaseRepository<,>open generic inEFRadixRepositoryRegistryfor runtime resolution.
NpgsqlDataOptions
| Property | Type | Default | Description |
|---|---|---|---|
ConnectionStringName |
string |
"DbConnection" |
Key used to resolve the connection string from IConfiguration |
UseJsonNet |
bool |
false |
Enables Newtonsoft.Json support for JSON columns |
EnableLegacyTimestampBehavior |
bool |
true |
Disables Npgsql's UTC-only enforcement for DateTime values |
DisableDateTimeInfinityConversions |
bool |
true |
Disables mapping of DateTime.MinValue/MaxValue to -infinity/infinity |
Connection string in appsettings.json:
{
"ConnectionStrings": {
"DbConnection": "Host=localhost;Database=mydb;Username=postgres;Password=secret"
}
}
Entity Configuration
Place IEntityTypeConfiguration<T> implementations in the same assembly as your DbContext. They are discovered and applied automatically.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class StudentConfiguration : IEntityTypeConfiguration<Student>
{
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.HasKey(s => s.Id);
builder.Property(s => s.Name).IsRequired().HasMaxLength(200);
builder.Property(s => s.Email).IsRequired().HasMaxLength(200);
}
}
Advanced Usage
Custom Queries with GetQueryable
GetQueryable() returns a no-tracking IQueryable<T>, which you can compose with standard LINQ:
var activeStudents = db.StudentRepository
.GetQueryable()
.Where(s => s.Name.Contains("John"))
.OrderBy(s => s.CreatedAt)
.ToListAsync();
For projections, joins, or pagination, compose directly on the queryable before materializing.
Using Without the Source Generator
If you prefer not to use the source generator, register with DynamicRepositoryContext<TContext> directly and access repositories via the generic Repository<T>() method:
// Registration
services.AddScoped<IRepositoryContext>(sp =>
new DynamicRepositoryContext<AppDbContext>(sp.GetRequiredService<AppDbContext>()));
// Usage — no named properties, generic access only
var repo = repositoryContext.Repository<Student>();
await repo.AddAsync(student);
Design Notes
- Immediate persistence — every write method calls
SaveChangesAsyncinternally. This keeps the API simple but means each operation is its own transaction. UseSaveChangesAsync()explicitly if you need to batch multiple tracked changes into a single transaction. - No-tracking reads —
GetQueryable()andGetByIdAsync()useAsNoTracking()for performance. Entities returned from these methods are not tracked by the context. - Provider registry —
EFRadixRepositoryRegistrydecouples the coreRepositoryContextfrom any specific provider. Provider packages register theirBaseRepository<,>type at startup, keeping the core layer provider-agnostic. - Compile-time generation — the source generator uses Roslyn's incremental pipeline, so regeneration is cache-aware and does not affect IDE responsiveness.
| 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 (>= 8.0.6)
- Microsoft.EntityFrameworkCore.UnitOfWork (>= 3.1.0)
- Npgsql (>= 8.0.3)
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 8.0.4)
- Npgsql.Json.NET (>= 8.0.3)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on EFRadix.Core.Postgres:
| Package | Downloads |
|---|---|
|
DotnetCqrsPgTemplate.Api
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.