v5.7.0
5.7.0 (2026-07-22)
Three new native relational providers and a complex-query surface that works the same way across every store — typed, pushed down, and honest about cost.
Three new packages: PostgreSQL, MySQL, SQL Server
eQuantic.Core.Data.PostgreSql,eQuantic.Core.Data.MySqlandeQuantic.Core.Data.SqlServer— the same contracts implemented directly on Npgsql, MySqlConnector and Microsoft.Data.SqlClient. No Entity Framework.- All three are thin dialects over the shared
eQuantic.Core.Data.Relationalengine: atomic batched commits (oneDbBatchin a transaction), generated keys read back (RETURNING/OUTPUT INSERTED; MySQL rejects backfill honestly), explicit transactions with read-your-writes, nativeOR/!=/NULLpushdown with C# semantics preserved, native paging plus keyset continuation, computed set-based updates, global query filters,Explain(), and fluent typed migrations. - PostgreSQL arrays are first-class:
= ANY, atomic append/remove,List<T>members.
Typed GroupBy with HAVING
var vips = await repo.GroupByAsync(
x => x.Customer,
g => new { g.Key, Orders = g.Count(), Revenue = g.Sum(x => x.Total) },
having: g => g.Sum(x => x.Total) > 100m && g.Count() >= 2);- Native
GROUP BY+HAVINGon PostgreSQL/MySQL/SQL Server, a$group+$matchpipeline on MongoDB, and a primary-key-restricted CQLGROUP BYon Cassandra — where CQL has noHAVING, the predicate's aggregates are computed on the cluster as extra select cells and filter the groups as they stream back; no extra rows travel. - Composite keys (
x => new { x.A, x.B }), whole-key or per-member projection, anonymous or POCO shapes. - One portable contract: the same projection shapes are accepted — and the same ones rejected, with guidance — on every provider.
Typed UNION / UNION ALL
var feed = UnionQuery.All(
Union.Of<Order>().Where(x => x.Status == "overdue")
.Select(x => new { Name = x.Customer, Origin = "order" }),
Union.Of<Buyer>().Select(x => new { x.Name, Origin = "buyer" }))
.OrderBy(row => row.Name).Take(20);
var rows = await unitOfWork.UnionAsync(feed);- One statement on the relational providers, one
$unionWithaggregation on MongoDB (UnionQuery.Distinctdeduplicates with$group). - Branches combine different entities into a common shape, tag rows with per-branch constants, and keep each entity's global query filter applied per branch (
IgnoringQueryFilters()opts a branch out) — a multi-tenant union stays tenant-scoped. - Ordering and paging apply to the combined result, on the store.
Aggregates everywhere
Min/Max/Average(IAggregateReadRepository<T>) now push down on all seven providers — SQL aggregates on the relational engine, CQL aggregates on Cassandra,$groupsingle-group aggregations on MongoDB,VALUE MIN/MAX/AVGon Cosmos DB (partition-scoped when the filter pins the key).
Extensible database functions
Db.Like,Db.Year/Month/Daymarkers interpret inside any filter lambda — and carry real C# bodies, so an unmapped function degrades to the gated client-side residual instead of breaking.- Instance functions (
ToLower,Trim,StartsWith/ContainsasLIKEwith dialect-neutral escaping) push down out of the box. - Bring your own: declare a static marker and map it per dialect with
Functions.Map("Reversed", (column, args) => $"REVERSE({column})").
Fixes
- Cassandra: the CQL renderer now refuses filter members that are not mapped columns (e.g. nested paths like
x.Name.Length) — they run as gated client-side residual instead of producing invalid CQL. - Cassandra: timestamp cells materialize into
DateTimemembers in grouped reads.
Also
FromSqlAsyncescape hatch (relational) — arbitrary SQL materialized by column name.- Relational
Includefor reference and collection navigations (one follow-upINquery per path). QueryFilters.FilterFor(Type, IServiceProvider)for runtime-typed resolution.
Everything validated against real servers: PostgreSQL, MySQL 8, SQL Server 2022, Cassandra 4.1, MongoDB replica set (Testcontainers) and the Cosmos DB Linux emulator in CI — 325 integration/unit tests locally plus the emulator suite.