Marten 9.14.1
Marten 9.14.1 is a patch release focused on a substantial round of LINQ query-translation improvements, plus event-store partitioning, high-water, and AoT fixes, and refreshed Weasel/JasperFx dependencies.
LINQ query translation
This release significantly expands what the LINQ provider can push down to PostgreSQL instead of falling back to slower strategies or throwing:
- Collection
Any(predicate)filters now translate to JSONPath and OR-of-containment strategies, and the old explode/ctidfallback has been replaced by a correlatedEXISTSstrategy.All()shapes and duplicated array fields moved onto the sameEXISTSstrategy. The net effect is correct, index-friendlier SQL for nested-collection predicates. - Indexing into complex child collections inside
Where()clauses is now supported (e.g.x.Children[0].Name == "..."). - Aggregates over collections —
Sum/Min/Max/Average— can now be used insideWhere()clauses. Regex.IsMatch()is translated inWhere()clauses.IComparable.CompareTo()now works for non-string comparables such asGuid(#4920), alongside broaderCompareTo()coverage,stringIsOneOfvia the?|operator, andCollectionIsEmptyviaICollectionAware.GinIndexJsonDataMember()was added for member-scoped expression GIN indexes.
#4916 — subclass queries now use duplicated fields and the base id
Querying a document subclass and filtering on a Duplicate()'d field or the base-class id previously emitted a JSONB filter (CAST(d.data ->> 'FarmId' as uuid)) instead of the real column, missing the duplicated column and the primary-key index:
o.Schema.For<Animal>().AddSubClass<Cow>().Duplicate(x => x.FarmId);
Query<Cow>().Where(x => x.FarmId == id) // now: d.farm_id = :p0 (was: CAST(d.data ->> 'FarmId' ...))
Query<Cow>().Where(x => x.Id == id) // now: d.id = :p0 (was: CAST(d.data ->> 'Id' ...))A subclass shares its parent's table, so the parent's column-backed members (duplicated fields, the id, the soft-delete flag) are now inherited by the subclass's query member resolution. Querying the parent type was already correct and is unchanged.
Event store, partitioning & daemon
- #4924 — hyphenated / GUID tenant ids under
UseTenantPartitionedEvents. Registering a tenant whose partition suffix contains a-(so every GUID tenant id) madeApplyAllConfiguredChangesToDatabaseAsync()throw42601because the per-tenantCREATE SEQUENCE/DROP SEQUENCEDDL emitted the identifier unquoted. The schema-apply statements are now quoted (matching the quick-append function and the imperative provisioning path), so hyphenated tenants migrate cleanly. Quote — not sanitize — so the append function can still resolve the sequence by its raw suffix. - #4915 — projection coordinator shutdown. The projection coordinator now drains on disposal, and via the Weasel 9.16.3 bump the advisory-lock
ObjectDisposedExceptionpath latches-and-rethrows so a HotCold cold node's leadership loop terminates instead of re-polling a disposed data source during shutdown. - #4913 — high-water scan under partitioning (JasperFx 2.26.0). Under
UseTenantPartitionedEventsthe store-global high-water agent was continuously runningselect max(seq_id) from mt_events, an unfiltered scan that fans out across every tenant partition on every poll. That store-global mark is not used to advance tenant projections (they advance per-tenant), so the recurring scan is now skipped under partitioning; tenant high water is driven by the per-tenant coordinator and poll timer. - #502 (#4922) —
GetProjectionStatusesAsyncnow resolves the correct named database.
AoT / trimming
- #4917 — corrected AoT annotations in the event graph.
- The
AddEventType/QueryRawEventDataOnlygeneric-constraint tightening was reversed, and event-mapping construction now routes through the cachedGenericFactoryCachewhile preserving the trimming root (#4930).
Dependencies
- Weasel 9.16.3 (#4932) — advisory-lock disposed-pool fix (marten#4915).
- JasperFx 2.26.0 — the #4913 high-water fix, plus 2.25.0's
ShardState.DatabaseIdentifier(#501).