Comparisons: Nextorm vs Dapper, linq2db and EF Core
This section is a high-level, dated comparison of Nextorm with the libraries it is most often measured against:
| Library | Profile |
|---|---|
| Dapper | Micro-ORM: hand-written SQL with object mapping; no LINQ and no change tracking. |
| linq2db | Mature LINQ-to-SQL ORM: associations, change tracking, a broad provider matrix and database-first tooling. |
| Entity Framework Core | Full ORM with change tracking, relationships, migrations and LINQ. |
Nextorm is a query builder and mapper without change tracking: it covers the analytic query surface and an explicit write surface, generates provider-portable SQL, and is benchmarked on the shipped scenarios.
The comparison has four parts:
- Capabilities — one construct-level matrix: what each library supports and where it does not.
- Provider features — per-engine API breadth against linq2db.
- Benchmarks — the shipped SQLite scenarios, with links to the full BenchmarkDotNet reports.
- Feature benchmarks — a per-feature, tiered comparison: no
Prepare()arms, one table per tier, competitors as columns.
How to read the marks
- yes — first-class support.
- partial — supported with a named limitation, or implementable but not implemented yet.
- no — not supported.
Marks are judgement calls against the public documentation of each library, as of 2026-10-04. Where a competitor has an open tracking issue for a gap, it is linked. A Nextorm cell names a restriction imposed by the database engine when one exists; that does not lower the mark. This is a summary — the guide and the API reference are authoritative for Nextorm, and each competitor's own documentation is authoritative for that competitor.
Scope and fairness
- Capability marks describe the library, not a specific database. Per-provider restrictions are noted inline.
- Benchmarks are micro-benchmarks on one machine and one provider (SQLite); they are a point-in-time signal, not a guarantee. The methodology and caveats are on the benchmarks page.
- The comparison is intentionally about overlap. Relationship modelling and change tracking are deliberately outside Nextorm's scope and are listed as such rather than counted as gaps.
Where Nextorm leads
Across the shared surface Nextorm matches or exceeds the three libraries, and on top of that it adds:
- A complete analytic query surface: every join type including
APPLY/LATERAL, derived-table joins, ClickHouse join strictness/GLOBAL,DISTINCT(plusDISTINCT ON/WITH TIES/TABLESAMPLE), CTEs (recursive, and data-modifying on PostgreSQL), window functions (named windows,GROUPS, frameEXCLUDE),ROLLUP/CUBE/GROUPING SETS, temporal tables (FOR SYSTEM_TIME), row locking and statement/table/index hints. - A complete explicit write surface with no change tracking:
INSERT/UPDATE/DELETE/fullMERGE, bulk insert (COPY/SqlBulkCopyor chunkedVALUES),CREATE TABLE AS SELECT/temporary tables and transactions — all explicit commands, noSaveChanges. - More of the type and mapping surface: native
Range<T>(and the[RangeColumns]pair mapping the others lack), arrays and higher-order array functions, row values/tuples, dynamic result schemas, captured-collection lookup and an optional mapped entity type. - Configurable SQL output: opt-in identifier quoting, naming conventions and keyword casing, overridable per command — whereas linq2db quotes by default and fixes names in its mapping schema.
- Extensibility as a first-class contract: query components let a third party add a new operator that changes the generated SQL (an added predicate, a reshaped row source) while keeping the plan cache, parameter binding and provider independence of an ordinary query — no friend access, no global registry, no raw SQL. linq2db and EF Core expose interceptors and function mappings, but no structural component contract with plan-cache integration.
- Zero-config NativeAOT migration. Inside the verified surface (SQLite, .NET 11 /
linux-x64) the only consumer change isPublishAot=true: no compiled model, no precompilation step, no analyzer/interceptor opt-in, no entity or query registration, no linker descriptors or roots. The competitors' contracts are heavier: EF Core requires a compiled model plus interceptor-based query precompilation and does not support dynamically composed queries; Dapper requires theDapper.AOTpackage, a[module: DapperAot]opt-in, anInterceptorsNamespacesproperty and statically known SQL; linq2db does not support NativeAOT officially. Measured on a 13 GB SQLite reporting app: nextorm published natively with no source changes (8.2 MB binary, 0.12 s, 30 MB RSS) against EF Core's 17.3 MB / 0.23 s / 42 MB after two code-generation workarounds. Coverage is still partial (SQLite only; #370) — the advantage is migration cost, not full AOT feature parity yet. See the NativeAOT guide. - Benchmarked performance: fastest on every end-to-end scenario, fastest on every prepared feature (with the smallest allocations on all but the IN-list), and ahead of regular linq2db and EF Core on the warm path (see Benchmarks).
Growth points
The honest balance to the section above — the in-scope work still ahead, kept separate from the deliberate boundaries:
- Warm-path performance: the implicit plan cache still trails Dapper by roughly 1.32–1.75× on the 4-table join, CTE, recursive CTE and IN-list (inline as well as captured), and its allocations stay above the prepared path; closing that gap is ongoing (see Benchmarks).
- EF Core integration: the
ToNextOrmadapter translates only a bounded operator subset —Select,Include/navigations,Join,GroupBy,EF.Property/EF.Functions,AsSplitQuery, raw-SQL roots and subqueries are not translated — and the MariaDB shared-connection and ClickHouse no-EF-adapter slices remain open (see EF Core integration). - Eager loading and relationships:
LoadWitheager loading covers finite nested graphs (level 2+, with a single graph-wide mode and per-level ordering/top-N) in split and expressible single-query;JoinIntojoins and groups on every declared key component, composite foreign, principal and junction keys included, while loading a many-to-many graph in a single eager-loading query remains out of scope. - Deeper query forms:
SelectMany/GroupJoinare not translated on the SQL providers,APPLY/LATERALcannot take a join projection, and in-memory correlation stops at depth one. - Dynamic SQL assembly: building SQL at runtime stays outside the builder surface.
- Provider-gated native types: native range/multirange, native JSON columns and arrays are not available on every provider; the others fall back to the pair/text mappings or reject them.
- Provider breadth: fewer providers than linq2db and EF Core (no Oracle, Firebird, DB2, SAP HANA, Informix, Sybase or SQL CE).
Relationship modelling, change tracking/SaveChanges, migrations and database-first scaffolding are
deliberate boundaries, not growth points — they are listed in
Limitations and out-of-scope features. Two composition boundaries are of the
same kind: a correlated APPLY extends an existing join chain but stops at eight total sources, and the
in-memory provider stops correlated subqueries at depth one, while every SQL provider nests them
arbitrarily. APPLY/LATERAL itself needs a lateral source: MariaDB 11.4, SQLite and ClickHouse refuse it
before execution, and the in-memory provider does not support it. These are API-shape and provider
boundaries, not missing SQL capabilities — the supported forms are covered by the
capabilities matrix and the guide.
Summary
For reading, reporting and explicit data modification over an existing schema, Nextorm is the stronger
choice: portable SQL across SQL Server, PostgreSQL, MySQL/MariaDB, SQLite and ClickHouse, a broadly
complete query surface, an explicit write surface with no change-tracking overhead, and benchmark results
at or above Dapper, EF Core and linq2db on the shipped scenarios. It also has the lightest NativeAOT
migration contract — PublishAot=true and nothing else — where EF Core needs a compiled model plus query
precompilation and Dapper needs the Dapper.AOT package with an interceptor opt-in. Dapper stays the
lightest option for
hand-written SQL with object mapping; linq2db and EF Core remain the better fit when the same layer must
also model relationships, track changes or generate the data layer from a live schema — surface Nextorm
deliberately leaves out.