FlexQuery.NET v3.1.1 Release Notes
Release date: 2026-07-04
Overview
v3.1.1 is a stability and performance release that hardens the execution pipeline, adds validation for grouped-query constraints, fixes Dapper case-insensitive SQL generation, enables filtered include hydration in Dapper, removes the legacy projection engine, and adds cache optimization for common reflection lookups.
What's Fixed
1. Execution Pipeline Ordering
Affected packages: FlexQuery.NET, FlexQuery.NET.EntityFrameworkCore
The EF Core pipeline was reordered to the canonical sequence, fixing regressions where pipeline stages executed in the wrong order and caused SQL errors on SQLite:
Before (incorrect for grouped queries on SQLite):
Filter → Sort → Count → Distinct → GroupBy → GrandTotals → Paging → Includes → Select
After (correct canonical order):
Filter → Distinct → Count → Sort → GroupBy → GrandTotals → Paging → Includes → Select
Key fixes:
- Count before Sort:
COUNT(*)now executes beforeORDER BY. Sort does not affect cardinality, and running it before Count caused SQLite decimalORDER BYinsideCOUNTsubqueries to fail with type mismatch errors. - Sort only in non-grouped path: Pre-GroupBy
ORDER BYon raw entity columns is unnecessary for grouped queries (sorting happens internally viaBuildGroupedSorts). Running it before GroupBy introduced decimal type issues on SQLite.
The base pipeline (QueryableExtensions) was similarly reordered for consistency.
2. High-Cardinality Paging Without Sort
Affected packages: FlexQuery.NET
When paging is requested without an explicit ORDER BY, the query engine now auto-generates an ORDER BY on the first selected field (or Id/Key/first property as fallback). This prevents non-deterministic paging results and eliminates database errors on SQL Server/Oracle that require ORDER BY for OFFSET/FETCH.
3. Dapper Case-Insensitive String Comparison
Affected packages: FlexQuery.NET.Dapper
Before: The CaseInsensitive option was ignored by the Dapper SQL generator. String comparisons always used exact case matching, producing different results than the EF Core provider.
After: SqlWhereBuilder now wraps string-type field comparisons with LOWER() when CaseInsensitive == true, matching EF Core's collation-delegated behavior:
-- Before (CaseInsensitive ignored):
WHERE [Name] = 'John'
-- After (CaseInsensitive == true):
WHERE LOWER([Name]) = 'john'Affects all comparison operators (=, !=, >, <, >=, <=, Contains, StartsWith, EndsWith). Threaded through SqlTranslator, SqlJoinBuilder, and SqlExistsTranslator.
4. Dapper Filtered Includes Hydration
Affected packages: FlexQuery.NET.Dapper
Before: FilteredIncludes (include paths with inline filter criteria parsed from query parameters) were silently ignored by the Dapper provider. Only flat Includes were hydrated.
After: DapperRowHydrator.HydrateFilteredIncludes<T>() extracts include paths from the IncludeNode tree and populates child entities with filtered data. FlexQueryDapperExtensions now checks both Includes and FilteredIncludes when determining whether to hydrate.
5. SelectTreeBuilder Root Scalars for FilteredIncludes
Affected packages: FlexQuery.NET
Before: When FilteredIncludes was present without Select or SelectTree, the root entity's scalar properties were not marked for materialization, causing empty root rows in Dapper results.
After: SelectTreeBuilder.Build() now calls root.MarkIncludeAllScalars() after processing FilteredIncludes, matching the existing behavior for Includes.
6. Validation Rules for Grouped Queries
Affected packages: FlexQuery.NET
Four new validation rules enforce correct usage of grouped-query constructs:
| Rule | Error Code | Rejects |
|---|---|---|
HavingWithoutGroupByRule |
HavingWithoutGroupBy |
Having filters without GroupBy or aggregates |
HavingAliasIntegrityRule |
HavingAliasMismatch |
Having references to non-declared aggregate aliases |
GroupByIncludeConflictRule |
GroupByIncludeConflict |
GroupBy combined with Include/Expand |
ExpandPathValidationRule |
IncludePathNotFound |
Include/Expand paths that don't exist on the entity type (recursive validation) |
All rules registered in QueryValidator constructor.
Performance Improvements
1. IsScalarType Cache
Affected packages: FlexQuery.NET
ReflectionCache.IsScalarType() now caches type classification results. Previously, every field in every query re-evaluated whether a Type is scalar via reflection. For projection-heavy queries on entities with many properties, this repeated evaluation caused measurable CPU overhead. Cached via BoundedConcurrentCache<Type, bool>.
2. IncludeBuilder MethodInfo Cache
Affected packages: FlexQuery.NET
IncludeBuilder caches MethodInfo lookups for EF.Property and related expression-building APIs. Previously rebuilt on every include path evaluation.
3. Legacy Projection Engine Removed
Affected packages: FlexQuery.NET
Removed the old ProjectionEngineTests.cs (104 lines) and related dead code from ProjectionOptimizer, ExpressionPrinter, and QueryResultExtensions. The modern ProjectionMetadata/ProjectionMetadataBuilder architecture handles all projection scenarios.
Maintenance
- XML documentation comments: Added descriptive XML docs to 4 new validation rules and resolved 125+ code analysis warnings across Core, EF Core, and Dapper projects.
ProjectionExecutionPlanmodel: New model class separating the projection plan from execution logic for cleaner separation of concerns.SqlFormatterandSqlParameterExtractor: New utility classes in EF Core for SQL formatting and parameter introspection (used by diagnostics).- Query diagnostics enhancements:
FlexQueryDiagnosticsCollectorimproved withTimelineEntrytracking,DiagnosticsDurationmeasurements, andConsoleExecutionListener. ProjectedFieldmodel: Extended withDbTypeandDirectionsupport for richer query parameter metadata.- Azure deployment workflow: Automated build and deployment to Azure App Service.
- GovernanceValidator startup validation: Added
ValidateConfiguration()for detectingBlockedFields∩AllowedFieldsoverlap at startup.
Breaking Changes
None. v3.1.1 is fully backward-compatible with v3.1.0.
Behavioral Changes
| Change | Impact | Mitigation |
|---|---|---|
| EF Core pipeline: Count before Sort | Grouped COUNT queries on SQLite no longer fail with decimal type errors | None (fix) |
| EF Core pipeline: Sort only in non-grouped path | Pre-GroupBy ORDER BY no longer emitted for grouped queries |
None (fix) |
Dapper CaseInsensitive now honored |
String comparisons may produce different SQL with LOWER() wrapping |
Set CaseInsensitive = false if exact case SQL is required |
Dapper FilteredIncludes now hydrated |
Previously ignored filtered includes now populate child entities | None (fix) |
| Auto-generated ORDER BY for paging | Queries with paging but no sort now produce deterministic results | None (fix) |
IsScalarType caching |
Slightly different memory profile (cache entries vs recomputation) | None (internal) |
New Test Coverage
| Test | Area | Verifies |
|---|---|---|
SqlTranslatorRegressionTests.CaseInsensitive_* |
Dapper | Case-insensitive SQL generation with LOWER() |
DialectTests.* (3 updated) |
Dapper | Assertions updated for CaseInsensitive defaults |
SqlFormatterTests (103 lines) |
EF Core | SQL formatting utility |
SqlParameterExtractorTests (82 lines) |
EF Core | Parameter extraction utility |
CacheKeyCorrectnessTests (163 new lines) |
Core | Cache key stability across query shapes |
Updated test assertions across the suite. 888 total tests pass (up from 874 in v3.1.0).
Upgrading
dotnet add package FlexQuery.NET --version 3.1.1
dotnet add package FlexQuery.NET.Dapper --version 3.1.1
dotnet add package FlexQuery.NET.EntityFrameworkCore --version 3.1.1
dotnet add package FlexQuery.NET.Parsers.Jql --version 3.1.1
dotnet add package FlexQuery.NET.Parsers.MiniOData --version 3.1.1
dotnet add package FlexQuery.NET.Adapters.AgGrid --version 3.1.1
dotnet add package FlexQuery.NET.Adapters.Kendo --version 3.1.1
dotnet add package FlexQuery.NET.AspNetCore --version 3.1.1No code changes required for existing v3.1.0 users.