SourceCrafter.EF.PostgREST.Provider
0.26.181.29
dotnet add package SourceCrafter.EF.PostgREST.Provider --version 0.26.181.29
NuGet\Install-Package SourceCrafter.EF.PostgREST.Provider -Version 0.26.181.29
<PackageReference Include="SourceCrafter.EF.PostgREST.Provider" Version="0.26.181.29" />
<PackageVersion Include="SourceCrafter.EF.PostgREST.Provider" Version="0.26.181.29" />
<PackageReference Include="SourceCrafter.EF.PostgREST.Provider" />
paket add SourceCrafter.EF.PostgREST.Provider --version 0.26.181.29
#r "nuget: SourceCrafter.EF.PostgREST.Provider, 0.26.181.29"
#:package SourceCrafter.EF.PostgREST.Provider@0.26.181.29
#addin nuget:?package=SourceCrafter.EF.PostgREST.Provider&version=0.26.181.29
#tool nuget:?package=SourceCrafter.EF.PostgREST.Provider&version=0.26.181.29
SourceCrafter.EF.PostgREST.Provider
An Entity Framework Core custom database provider that targets a PostgREST HTTP API instead of a traditional database connection. Write standard LINQ queries and SaveChanges() calls — the provider translates them into PostgREST-compatible HTTP requests automatically.
Features
- Zero-config LINQ → PostgREST translation —
WHERE,SELECT,ORDER BY,SKIP/TAKEall map to PostgREST query-string parameters. - Full CRUD via
SaveChanges—Added→POST,Modified→PATCH,Deleted→DELETE. - Cascade insert — insert a parent entity together with its related children in a single
SaveChangesAsync()call. - Bulk operations —
ExecuteUpdateAsyncandExecuteDeleteAsynctranslate toPATCH/DELETEwith query-string filters (no entity tracking required). - Eager loading —
Include/ThenInclude, including filtered includes (.Include(p => p.Children.Where(...))). - Lazy loading —
Find/FindAsync - Projection support — anonymous types, scalars,
ValueTuple, record DTOs, class member-init, nested shapes, and nested related-collection projections. - Result materialization helpers —
ToListAsync,ToDictionaryAsync,FirstOrDefaultAsync, synchronous.ToList(). - Filter operators —
eq,neq,gt,gte,lt,lte,like,ilike,is null, OR predicates, NOT predicates,INlists. - JWT authentication — pass a bearer token through provider options.
- Non-default schema support —
Accept-Profile/Content-Profileheaders. IHttpClientFactoryintegration — no rawHttpClientinstances.System.Text.Jsonsource generators — AOT-safe serialization.- Roslyn Analyzer / Entity Code Generator — generates strongly-typed entity classes from a live PostgREST schema, emitting
[Key]for single-column PKs and[PrimaryKey(...)]for composite PKs. - Targets .NET 10 and EF Core 10.
Installation
dotnet add package SourceCrafter.EF.PostgREST.Provider
Quick Start
1. Define your entities
public class Categoria
{
public int Id { get; set; }
public string Nombre { get; set; } = string.Empty;
}
2. Create your DbContext
using Microsoft.EntityFrameworkCore;
using PosgREST.DbContext.Provider.Core.Extensions;
public class AppDbContext : DbContext
{
private readonly string _baseUrl;
public AppDbContext(string baseUrl) => _baseUrl = baseUrl;
public DbSet<Categoria> Categorias => Set<Categoria>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UsePostgRest(_baseUrl);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Categoria>(e =>
{
e.HasKey(x => x.Id);
e.Property(x => x.Id).ValueGeneratedOnAdd();
e.Property(x => x.Nombre).HasMaxLength(50);
});
}
}
3. Query data
await using var db = new AppDbContext("http://localhost:3000");
// SELECT all
var all = await db.Categorias.ToListAsync();
// Filtered + sorted + paged
var page = await db.Categorias
.Where(c => c.Nombre.StartsWith("Test"))
.OrderBy(c => c.Nombre)
.Skip(0).Take(10)
.ToListAsync();
// Projection — anonymous type
var names = await db.Categorias
.Select(c => new { c.Id, c.Nombre })
.ToListAsync();
// Projection — nested related-collection
var products = await db.Producto
.Select(p => new ProductDto
{
Id = p.Id,
Name = p.Nombre,
Purchases = p.Compras
.Select(c => new PurchaseDto { Id = c.Id, Quantity = c.Cantidad })
.ToList()
})
.ToListAsync();
// Materialize as dictionary
var dict = await db.Categorias.ToDictionaryAsync(c => c.Id, c => c.Nombre);
// Synchronous query
var sync = db.Categorias.OrderBy(c => c.Id).Take(3).ToList();
4. Mutate data
// INSERT
var cat = new Categoria { Nombre = "NewCategory" };
db.Categorias.Add(cat);
await db.SaveChangesAsync();
Console.WriteLine(cat.Id); // server-assigned PK
// CASCADE INSERT — parent + children in one call
var prod = new Producto { Nombre = "Widget" };
prod.Compras.Add(new Compra { Cantidad = 5, Precio = 15, Moneda = "USD" });
await db.Producto.AddAsync(prod);
await db.SaveChangesAsync(); // POSTs parent, then each child
// UPDATE
cat.Nombre = "Updated";
await db.SaveChangesAsync();
// DELETE
db.Categorias.Remove(cat);
await db.SaveChangesAsync();
5. Bulk / batch operations
No entity tracking needed — these translate directly to PostgREST PATCH/DELETE with a query-string filter.
// Bulk update — PATCH /categorias?id=in.(2,3) { "nombre": "Renamed" }
var updated = await db.Categorias
.Where(c => ids.Contains(c.Id))
.ExecuteUpdateAsync(s => s.SetProperty(c => c.Nombre, "Renamed"));
// Bulk delete — DELETE /categorias?id=in.(2,3)
var deleted = await db.Categorias
.Where(c => ids.Contains(c.Id))
.ExecuteDeleteAsync();
6. Eager loading
// Include related collections (with optional filter)
var products = await db.Producto
.Include(p => p.Compras.Where(c => c.Tasa == 0))
.ThenInclude(c => c.UnidadMedida)
.Include(p => p.Ventas)
.ToListAsync();
7. Lazy loading
// Loads lazily related collections and parent relation properties on demand and cache-first hit
var products = await db.Producto.FindAsync(idParm);
LINQ → PostgREST Translation Reference
| LINQ / EF Core | PostgREST query-string |
|---|---|
.Where(e => e.Id == 1) |
?id=eq.1 |
.Where(e => e.Name != "x") |
?name=neq.x |
.Where(e => e.Age > 18) |
?age=gt.18 |
.Where(e => e.Age >= 18) |
?age=gte.18 |
.Where(e => e.Age < 65) |
?age=lt.65 |
.Where(e => e.Name.Contains("foo")) |
?name=like.*foo* |
.Where(e => e.Name.StartsWith("A")) |
?name=like.A* |
.Where(e => e.Name.EndsWith("z")) |
?name=like.*z |
.Where(e => !e.Name.Contains("foo")) |
?name=not.like.*foo* |
.Where(e => e.Id == 2 \|\| e.Id == 3) |
?or=(id=eq.2,id=eq.3) |
.Where(e => e.Name == null) |
?name=is.null |
.Where(e => e.Name != null) |
?name=not.is.null |
.Where(e => ids.Contains(e.Id)) |
?id=in.(1,2,3) |
.OrderBy(e => e.Name) |
?order=name.asc |
.OrderByDescending(e => e.Name) |
?order=name.desc |
.Skip(10).Take(5) |
?offset=10&limit=5 |
.Select(e => new { e.Id, e.Name }) |
?select=id,name |
.ExecuteUpdateAsync(s => s.SetProperty(...)) |
PATCH /{table}?{filter} |
.ExecuteDeleteAsync() |
DELETE /{table}?{filter} |
.Include(e => e.Children) |
?select=*,children(*) (embedded) |
.Include(e => e.Children.Where(...)) |
filtered embedded resource |
.FindAsync(idParam) |
loads embedded resources on demand lazily |
EntityState → HTTP Verb
EF Core EntityState |
HTTP Verb | PostgREST Pattern |
|---|---|---|
Added |
POST |
POST /{table} |
Modified |
PATCH |
PATCH /{table}?{pk}=eq.{value} |
Deleted |
DELETE |
DELETE /{table}?{pk}=eq.{value} |
Unchanged (query) |
GET |
GET /{table}?select={cols}&{filters} |
Bulk Update (ExecuteUpdateAsync) |
PATCH |
PATCH /{table}?{filter} |
Bulk Delete (ExecuteDeleteAsync) |
DELETE |
DELETE /{table}?{filter} |
Roslyn Analyzer & Entity Code Generator
The PostgREST.DbContext.Provider.Analyzers package ships a Roslyn analyzer and a source-level entity code generator that can scaffold strongly-typed C# entity classes directly from a live PostgREST schema endpoint.
Generated code rules
| Scenario | Generated attribute |
|---|---|
| Single-column primary key | [Key] on the property |
| Composite primary key | [PrimaryKey(nameof(Col1), nameof(Col2))] on the class + using Microsoft.EntityFrameworkCore; |
| Timestamp / date columns | Mapped to DateTimeOffset / DateOnly |
| Nullable columns | Emitted as nullable reference / value types |
Usage
Reference the analyzer project as an analyzer in your .csproj:
<ItemGroup>
<ProjectReference Include="..\PostgREST.DbContext.Provider.Analyzers\..."
ReferenceOutputAssembly="true"
OutputItemType="analyzer" />
</ItemGroup>
The generator produces one .cs file per table, ready to be used as EF Core entities.
Configuration Options
| Option | Default | Description |
|---|---|---|
| Base URL | (required) | PostgREST root URL, e.g. http://localhost:3000 |
| Bearer token | null |
JWT passed as Authorization: Bearer {token} |
| Schema | public |
PostgreSQL schema (Accept-Profile / Content-Profile) |
Requirements
| Dependency | Version |
|---|---|
| .NET | 10 |
| EF Core | 10.0.x |
| PostgREST | 12+ |
Contributing
Pull requests are welcome. For significant changes, please open an issue first to discuss what you would like to change.
License
| 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.3)
- Microsoft.EntityFrameworkCore.Proxies (>= 10.0.3)
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 |
|---|---|---|
| 0.26.181.29 | 134 | 6/30/2026 |
| 0.26.179.460 | 121 | 6/28/2026 |
| 0.26.179.247 | 116 | 6/28/2026 |
| 0.26.124.80 | 114 | 5/4/2026 |
| 0.26.122.470 | 111 | 5/2/2026 |
| 0.26.121.245 | 111 | 5/1/2026 |
| 0.26.121.71 | 115 | 5/1/2026 |
| 0.26.116.320 | 123 | 4/26/2026 |
| 0.26.114.305 | 113 | 4/24/2026 |
| 0.26.111.329 | 111 | 4/21/2026 |
| 0.26.111.327 | 110 | 4/21/2026 |
| 0.26.111.324 | 111 | 4/21/2026 |
| 0.26.111.323 | 106 | 4/21/2026 |
| 0.26.111.322 | 110 | 4/21/2026 |
| 0.26.111.311 | 111 | 4/21/2026 |
| 0.26.111.48 | 120 | 4/21/2026 |
| 0.26.110.409 | 106 | 4/20/2026 |
| 0.26.55.407 | 125 | 2/24/2026 |
| 0.26.55.151 | 125 | 2/24/2026 |
| 0.26.55.105 | 126 | 2/24/2026 |