Skip to content

v3.1.1

Latest

Choose a tag to compare

@github-actions github-actions released this 04 Jul 07:58

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 before ORDER BY. Sort does not affect cardinality, and running it before Count caused SQLite decimal ORDER BY inside COUNT subqueries to fail with type mismatch errors.
  • Sort only in non-grouped path: Pre-GroupBy ORDER BY on raw entity columns is unnecessary for grouped queries (sorting happens internally via BuildGroupedSorts). 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.
  • ProjectionExecutionPlan model: New model class separating the projection plan from execution logic for cleaner separation of concerns.
  • SqlFormatter and SqlParameterExtractor: New utility classes in EF Core for SQL formatting and parameter introspection (used by diagnostics).
  • Query diagnostics enhancements: FlexQueryDiagnosticsCollector improved with TimelineEntry tracking, DiagnosticsDuration measurements, and ConsoleExecutionListener.
  • ProjectedField model: Extended with DbType and Direction support for richer query parameter metadata.
  • Azure deployment workflow: Automated build and deployment to Azure App Service.
  • GovernanceValidator startup validation: Added ValidateConfiguration() for detecting BlockedFieldsAllowedFields overlap 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.1

No code changes required for existing v3.1.0 users.