ZeroAlloc.ORM.Abstractions
0.2.0
See the version list below for details.
dotnet add package ZeroAlloc.ORM.Abstractions --version 0.2.0
NuGet\Install-Package ZeroAlloc.ORM.Abstractions -Version 0.2.0
<PackageReference Include="ZeroAlloc.ORM.Abstractions" Version="0.2.0" />
<PackageVersion Include="ZeroAlloc.ORM.Abstractions" Version="0.2.0" />
<PackageReference Include="ZeroAlloc.ORM.Abstractions" />
paket add ZeroAlloc.ORM.Abstractions --version 0.2.0
#r "nuget: ZeroAlloc.ORM.Abstractions, 0.2.0"
#:package ZeroAlloc.ORM.Abstractions@0.2.0
#addin nuget:?package=ZeroAlloc.ORM.Abstractions&version=0.2.0
#tool nuget:?package=ZeroAlloc.ORM.Abstractions&version=0.2.0
<h1 align="center">ZeroAlloc.ORM</h1>
<p align="center">Source-generator-based, NativeAOT-clean raw-SQL data access for .NET. Annotate <code>partial</code> methods with <code>[Query]</code> / <code>[Command]</code> / <code>[StoredProcedure]</code>; the generator emits typed parameter binding + materialization against <a href="https://github.com/MarcelRoozekrans/AdoNet.Async">AdoNet.Async</a>. Zero runtime reflection.</p>
Status: Pre-release. v0.1 milestone in progress. Authoritative design lives at
docs/design/2026-05-30-v1.0-design.md. Working backlog atdocs/plans/za-orm-backlog.md.
What it is
A source-generator-driven data-access library that fills in the gap between two extremes adopters currently choose from:
- EF Core — full LINQ-to-SQL ORM, but its precompile-queries pipeline currently collides with co-resident source generators (e.g. ZA.Rest), blocking NativeAOT publish in template stacks like ZeroAlloc.Templates.
- Hand-written ADO.NET — works under AOT, but every repository becomes a hand-shaped tower of
CreateCommand/CreateParameter/ReadAsynccalls.
ZeroAlloc.ORM is the middle path: write the SQL string in an attribute, declare the partial method signature, let the source generator emit the ADO.NET pipeline. Zero runtime reflection, fully AOT-publishable, idiomatic with the rest of the ZeroAlloc ecosystem (consumes AdoNet.Async, dogfoods ZeroAlloc.ValueObjects, shares the convention catalog with ZeroAlloc.Mapping).
Packages
| Package | Description | NativeAOT |
|---|---|---|
| ZeroAlloc.ORM | Runtime helpers + ActivitySource for observability. Depends on AdoNet.Async. |
✅ |
| ZeroAlloc.ORM.Abstractions | Public attribute surface ([Query], [Param], [StoreAsString]) + exception types. Remaining attributes ([Command], [StoredProcedure], [Materialize]) land in their implementing milestones (v0.4–v0.5). |
✅ |
| ZeroAlloc.ORM.Generator | Roslyn incremental source generator. Build-time only. | N/A |
| ZeroAlloc.TypeConversions | Shared convention-discovery catalog (value-objects, enums, composites). Build-time only. | N/A |
Quick Start
Scalar query
using System.Data.Async;
using System.Threading;
using System.Threading.Tasks;
using ZeroAlloc.ORM;
public sealed partial class Repo(IAsyncDbConnection connection)
{
[Query("SELECT count(*) FROM Orders")]
public partial Task<int> CountOrdersAsync(CancellationToken ct);
}
The source generator emits the open / execute / close pipeline against AdoNet.Async's IAsyncDbConnection. Zero runtime reflection; the emit composes through global::-qualified identifiers so it doesn't care about the consumer's using directives.
Row materialization (FlatRow)
public sealed record OrderRow(int Id, int CustomerId, decimal Total);
public sealed partial class OrderRepo(IAsyncDbConnection connection)
{
[Query("SELECT Id, CustomerId, Total FROM Orders WHERE Id = @id")]
public partial Task<OrderRow?> GetByIdAsync(int id, CancellationToken ct);
}
Positional record + matching SELECT column order = no mapping config. Nullable return = empty result set yields null.
Available in v0.1
[Query]with scalar (Task<int>,Task<T?>) and FlatRow (Task<TRow?>) return shapes.- 14 primitive types in parameter binding (int / long / short / byte / bool / decimal / double / float / string / Guid / DateTime / DateTimeOffset / TimeSpan / byte[]) + nullable variants.
[Param(Name = "...")]SQL-side parameter name override.- Compile-time diagnostics (ZAO001–ZAO009 + informational ZAO020–ZAO022) for signature contract violations.
- NativeAOT-clean publish (verified by
aot-smokeCI gate).
Added in v0.2
Value-object columns — types annotated with
[ValueObject]from ZeroAlloc.ValueObjects (with a staticFromfactory and aValueproperty) bind through their underlying primitive. Parameters unwrap toValue; reads wrap viaT.From(primitive).[ValueObject] public readonly partial struct CustomerId { public int Value { get; } public CustomerId(int value) { Value = value; } public static CustomerId From(int value) => new(value); } public sealed record CustomerRow(CustomerId Id, string Name); public sealed partial class CustomerRepo(IAsyncDbConnection connection) { [Query("SELECT Id, Name FROM Customers WHERE Id = @id")] public partial Task<CustomerRow?> GetAsync(CustomerId id, CancellationToken ct); }Enums (default int round-trip) — any
enumparameter or column binds as its underlying integer (reader.GetInt32+ cast on read; cast to underlying primitive on bind).Enums (string round-trip) — annotate the
enumtype with[StoreAsString]to round-trip as the member name (reader.GetString+Enum.Parse<T>on read; member-name bind).Domain-entity classes — plain
classtypes with a single multi-arg public ctor materialize via column-name-keyed reads (__reader.GetOrdinal("ColumnName")). SELECT column order is irrelevant; each ctor parameter resolves to its matching column by name. Records keep the positionalFlatRowpath.Single-arg record discovery + static
Fromfactory discovery — wrappers without[ValueObject]still resolve when ConventionDiscovery can find an obvious construction strategy.New diagnostics ZAO040–ZAO044 — materialization-side failures (no construction strategy, conflicting strategies, unresolved ctor parameters, etc.) surface at build time with focused messages.
Deferred to later milestones: [Command] / [StoredProcedure] (v0.4), IAsyncEnumerable<T> streaming (v0.3), multi-result-set tuples (v0.3), multi-column composite types (v0.5).
Design + roadmap
- Design:
docs/design/2026-05-30-v1.0-design.md— 5-section v1.0 design covering architecture, generator surface, convention discovery, diagnostics, test strategy, milestones. - Backlog:
docs/plans/za-orm-backlog.md— priority-banded task list. New findings during implementation get appended. - Ecosystem context: sits alongside ZeroAlloc.Mediator, ZeroAlloc.Mapping, ZeroAlloc.ValueObjects, ZeroAlloc.Validation. Substrate is AdoNet.Async (AOT-compatible since v1.x).
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
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ZeroAlloc.ORM.Abstractions:
| Package | Downloads |
|---|---|
|
ZeroAlloc.ORM
Source-generator-based, NativeAOT-clean raw-SQL data access for .NET. Annotate partial methods with [Query]; the generator emits typed parameter binding + materialization against AdoNet.Async's IAsyncDbConnection. Zero runtime reflection. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.0 | 528 | 6/4/2026 |
| 1.5.0 | 614 | 6/3/2026 |
| 1.4.0 | 109 | 6/3/2026 |
| 1.3.0 | 102 | 6/3/2026 |
| 1.2.0 | 328 | 6/2/2026 |
| 1.1.0 | 186 | 6/1/2026 |
| 1.0.0 | 112 | 6/1/2026 |
| 0.7.0 | 113 | 6/1/2026 |
| 0.6.0 | 110 | 6/1/2026 |
| 0.5.0 | 116 | 5/31/2026 |
| 0.4.0 | 121 | 5/31/2026 |
| 0.3.0 | 106 | 5/31/2026 |
| 0.2.0 | 114 | 5/30/2026 |
| 0.1.0 | 111 | 5/30/2026 |