v6.2.0
v6.2.0 — measured, diagnosed, generated
This release is the performance-and-tooling round: published benchmarks that drove two engine
optimizations to the raw-driver floor, compile-time model diagnostics, and source-generated
entity accessors — both shipped inside the core package, no extra installs.
Published benchmarks — and the loop they exist for
The repository now carries a comparative suite (benchmarks/) against EF Core, Dapper and raw
Npgsql over a real PostgreSQL 17: point read, filtered set, projection, paging, single insert,
100-row commit, set-based update. Results, methodology and the honest reading live in the docs:
Operations → Benchmarks.
The first run named two losses — and both were fixed at the engine level and re-measured:
| Scenario | First run | Now | The fix |
|---|---|---|---|
| Projection (500 rows) | 1.29× of raw | 0.92× | reader-direct projectors (no entity shells, no per-query JIT) + a structural projector cache |
| Single insert + commit | 1.84× | 1.00× | one-statement flushes skip the local transaction (a single statement is atomic on its own) |
Where the table stands (Apple M4 Pro, .NET 10, ShortRun): every read scenario at or below the raw
Npgsql baseline within noise, ahead of EF Core across the board; the batch flush at hand-written
DbBatch speed — ~2× faster than EF Core, ~10× faster than per-row Dapper inserts.
Compile-time model diagnostics (EQD001–EQD011)
eQuantic.Core.Data now ships a Roslyn analyzer (bundled — every consumer gets it): the modeling
misuses that are wrong on every provider surface as warnings while typing, with the fix in the
message — a concurrency token no store can version, ambiguous [PartitionKey]/[ClusteringKey]
orders, multiple [EntityKey] members, invalid [Facet]s, contradictory [Unmapped], and more.
Provider-relative rules deliberately stay at runtime, where the provider is known and the message
can be exact. The full table.
Source-generated entity accessors
A source generator (also bundled) emits reflection-free accessors — construction, member reads and
writes as direct code — for every entity in the consuming compilation, registered automatically.
Relational materialization and column reads use them when present; reflection remains the
fallback contract, so nothing changes for assemblies compiled without the generator, and types
the generated code could not honor faithfully (init-only setters, no accessible parameterless
constructor) stay on the reflection path by design.
Measured effect on the benchmarks: within noise — stated plainly in the docs, because that is the
honest finding. The accessors exist to remove the reflection dependence itself: the groundwork for
trimming/NativeAOT support.
Also in this release
- Mapped reads (
GetMappedAsync, paged maps) narrow their SELECT and build results in one pass. - The benchmark harness documents its methodology (per-stack idiomatic setup, state isolation) and
reproduces with one command — Docker included, container owned by the run.
Verification
Suites green across the round on real stores: PostgreSQL 53 (through the generated accessors),
SQL Server 13, MySQL 16, MongoDB 131, Cosmos DB 41, Cassandra 94, core 62, analyzers 13.
Compatibility: no breaking changes. Requires eQuantic.Core.DataModel 4.0.0 /
eQuantic.Core.Domain 4.0.0 (as since v6.0.0).