Skip to content

v3.0.5

Choose a tag to compare

@github-actions github-actions released this 24 Jun 04:19

FlexQuery.NET v3.0.5 Release Notes

Release date: 2026-06-24

Overview

v3.0.5 enables expression caching by default, adds ReflectionCache for centralized property metadata caching, hardens DynamicTypeBuilder with bounded FIFO eviction, fixes an EF Core operator handler cache poisoning bug, and expands regression test coverage across all caching layers.


What's New

1. Expression Caching Enabled by Default

FlexQueryCacheSettings.EnableCache is now true by default (was false). Expression trees for predicates and projections are cached after the first build for each unique query shape. Cache keys are deterministic and cover all query dimensions (filter, sort, select, group-by, aggregates, includes, paging). Bounded at 2000 entries per cache instance with FIFO eviction.

Caching is automatically disabled when ExpressionMappings (custom field→expression mappings) are present.

To disable:

FlexQueryCacheSettings.EnableCache = false;

2. EF Core Operator Cache Poisoning Fix

UseEfCoreOperators() now sets a marker in options.Items["__EfCoreOperators"] that is included in the expression cache key. Previously, the OperatorHandlerRegistry global static state was not part of the cache key — identical QueryOptions with different operator handler registrations would share a cached expression, returning wrong SQL. Now EF Core operator mode and default operator mode produce distinct cache keys.

3. ReflectionCache

New FlexQuery.NET.Caching.ReflectionCache centralizes all property metadata lookups across the validation, projection, wildcard expansion, and grouping pipelines. Four cache methods backed by ConcurrentDictionary:

  • GetProperty(Type, string) — case-insensitive, per (type, name)
  • GetProperties(Type) — per type
  • TryResolvePropertyChain(Type, string, out chain) — dot-path resolution with collection traversal
  • TryGetCollectionElementType(Type, out elementType)IEnumerable<T> interface scan

Refactored call sites (14 files): SafePropertyResolver, ProjectionBuilder, DefaultProjectionRule, FieldAccessValidator, AggregateResultBuilder, ProjectionOptimizer, QueryBuilder, FlatProjectionBuilder (6 sites), TypeHelper.

4. DynamicTypeBuilder Cache Hardening

Added bounded FIFO eviction via FlexQueryCacheSettings.MaxCacheSize. Cache key changed from Type.GetHashCode() (unstable) to Type.FullName (stable). Added Clear() and Count API. Added ArgumentNullException guard on null input.

5. Cache Key Correctness Tests

3 new tests in CacheKeyCorrectnessTests:

Test Verifies
CanCache_WithExpressionMappings_ReturnsFalse ExpressionMappings disables caching
CacheKey_IdenticalQuery_DifferentEntityType_DifferentKey Entity type is in the cache key
SortOrder_DifferentFieldOrder_DifferentKey Sort order is preserved in the key

6. New Test Coverage

Area Tests Focus
ReflectionCacheTests 35 GetProperty, GetProperties, chain resolution, collection detection, thread safety, cache-miss consistency, path edge cases
DynamicTypeBuilderTests 14 Shape generation, FIFO eviction, thread safety, null guard, cache reuse
CacheKeyCorrectnessTests 8 Filter/select/sort/entity-type differentiation, ExpressionMappings gate
CacheIsolationTests 3 ParserCache deep-clone isolation

Migration Guide

Expression Caching

No code changes required. Caching is transparent — cache keys are deterministic and the cache is bounded. If memory pressure is a concern:

FlexQueryCacheSettings.EnableCache = false;  // Disable globally
// Or per-query:
options.EnableCache = false;  // Disable for a single query

ReflectionCache

No code changes required. All existing code paths now delegate to ReflectionCache internally. The public API is unchanged.

DynamicTypeBuilder

No code changes required. The cache is now bounded — if you observe cache eviction of projection types, increase FlexQueryCacheSettings.MaxCacheSize (default 2000).


Upgrading

dotnet add package FlexQuery.NET --version 3.0.5
dotnet add package FlexQuery.NET.Adapters.AgGrid --version 3.0.5
dotnet add package FlexQuery.NET.Dapper --version 3.0.5

Full test suite: 827 tests passing, zero regressions.