FlexQuery.NET.Parsers.Jql
3.0.5
See the version list below for details.
dotnet add package FlexQuery.NET.Parsers.Jql --version 3.0.5
NuGet\Install-Package FlexQuery.NET.Parsers.Jql -Version 3.0.5
<PackageReference Include="FlexQuery.NET.Parsers.Jql" Version="3.0.5" />
<PackageVersion Include="FlexQuery.NET.Parsers.Jql" Version="3.0.5" />
<PackageReference Include="FlexQuery.NET.Parsers.Jql" />
paket add FlexQuery.NET.Parsers.Jql --version 3.0.5
#r "nuget: FlexQuery.NET.Parsers.Jql, 3.0.5"
#:package FlexQuery.NET.Parsers.Jql@3.0.5
#addin nuget:?package=FlexQuery.NET.Parsers.Jql&version=3.0.5
#tool nuget:?package=FlexQuery.NET.Parsers.Jql&version=3.0.5
FlexQuery.NET
Dynamic filtering, sorting, paging, and projection for IQueryable in .NET.
FlexQuery.NET is a lightweight and powerful dynamic query engine for .NET. It allows you to transform complex API query parameters into optimized, EF Core-translatable expression trees with a single line of code.
⚡ Key Features
- Dynamic Querying: Powerful DSL, JQL, and JSON-based filtering.
- IQueryable-Native: 100% server-side translation—no client-side evaluation.
- Advanced Projection: Automatic SQL
SELECToptimization including nested includes. - Governance & Security: Built-in field-level validation and operator restrictions.
- High Performance: Thread-safe expression caching for ultra-low latency.
🚀 Quick Start
1. Installation
dotnet add package FlexQuery.NET
dotnet add package FlexQuery.NET.EntityFrameworkCore
dotnet add package FlexQuery.NET.Dapper
dotnet add package FlexQuery.NET.AspNetCore
dotnet add package FlexQuery.NET.Adapters.AgGrid
2. Entity Framework Core (Default)
Securely execute a dynamic query directly from your controller against an EF Core DbContext. The provider handles translation, pagination, and async execution automatically.
[HttpGet("users")]
public async Task<IActionResult> GetUsers([FromQuery] FlexQueryParameters parameters)
{
var result = await _context.Users.FlexQueryAsync(parameters, options =>
{
options.AllowedFields = new HashSet<string> { "Id", "Name", "Email", "Status" };
options.StrictFieldValidation = true;
options.UseNoTracking = true; // Optimization for read-only queries
});
return Ok(result);
}
3. Dapper & Raw SQL Integration
For high-performance API endpoints or non-EF Core projects, use the Dapper provider to generate secure, dialect-aware, fully parameterized SQL queries.
using FlexQuery.NET.Dapper;
using FlexQuery.NET.Dapper.Dialects;
[HttpGet("users")]
public async Task<IActionResult> GetUsersDapper([FromQuery] FlexQueryParameters parameters)
{
using var connection = new SqlConnection("Server=...;");
// Generates parameterized SQL, handles dialects (SQL Server, Postgres, MySQL, etc.)
var result = await connection.FlexQueryAsync<User>(parameters, options =>
{
options.Dialect = new SqlServerDialect();
options.AllowedFields = new HashSet<string> { "Id", "Name", "Email" };
});
return Ok(result);
}
4. AG Grid Adapter
FlexQuery.NET.Adapters.AgGrid parses AG Grid's Enterprise Server-Side Row Model JSON payloads natively, translating pagination, filtering, sorting, row grouping, and aggregations into FlexQuery operations.
[HttpPost("grid")]
public async Task<IActionResult> GetGridData([FromBody] AgGridRequest request)
{
// 1. Parse AG Grid request into canonical QueryOptions
var options = request.ToQueryOptions();
// 2. Execute via EF Core or Dapper
var result = await _context.Users.FlexQueryAsync<User>(options, opts =>
{
opts.AllowedFields = new HashSet<string> { "Id", "Name", "Status", "CreatedAt" };
});
// 3. Return format expected by AG Grid.
// Grouped SSRM responses should prefer ResultCount when available.
return Ok(new { rowData = result.Data, rowCount = result.ResultCount ?? result.TotalCount });
}
5. MiniOData Parser
Migrating from OData? FlexQuery.NET.Parsers.MiniOData acts as a drop-in bridge, automatically detecting and parsing OData syntax ($filter, $orderby, $top, $skip) on the same endpoint that handles JSON and JQL queries.
// Program.cs
builder.Services.AddFlexQueryMiniOData();
// Controller
[HttpGet("products")]
public async Task<IActionResult> GetProducts([FromQuery] FlexQueryParameters parameters)
{
// Auto-detects OData parameters like:
// ?$filter=Price gt 50 and Category eq 'Electronics'&$orderby=Name desc
var result = await _context.Products.FlexQueryAsync(parameters);
return Ok(result);
}
6. Example Query Requests
FlexQuery unifies multiple formats under the same API without configuration:
# Native DSL
GET /api/users?filter=age:gt:18&sort=createdAt:desc&page=1&pageSize=20
# JQL Syntax
GET /api/users?filter=Age > 18 AND Status = 'Active'
# OData Syntax (requires MiniOData package)
GET /api/users?$filter=Age gt 18 and Status eq 'Active'
📚 Documentation
Counting Semantics
QueryResult<T> exposes three different row counts. They answer different questions:
| Property | Meaning |
|---|---|
TotalCount |
Filtered source records |
ResultCount |
Shaped rows before paging |
Data.Count |
Current page rows |
For a normal query, TotalCount and ResultCount usually match:
1432 products
pageSize = 20
TotalCount = 1432
ResultCount = 1432
Data.Count = 20
For grouped or shaped queries, ResultCount is the count most UI grids need for paging:
1432 products
GROUP BY Brand
4 brand groups
TotalCount = 1432
ResultCount = 4
Data.Count = current page of groups
HAVING is applied before ResultCount:
1432 products
GROUP BY Brand
HAVING SUM(Quantity) > 100
2 groups remain
TotalCount = 1432
ResultCount = 2
For AG Grid SSRM grouping, prefer:
var rowCount = result.ResultCount ?? result.TotalCount;
TotalCount semantics are unchanged for backward compatibility.
For detailed guides, API references, and advanced scenarios, visit our documentation site:
👉 https://flexquery.vercel.app
Quick Links
- Getting Started
- Query Composition
- Security & Field Access
- Dapper Provider
- AG Grid Integration
- MiniOData Parser
📄 License
FlexQuery.NET is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FlexQuery.NET (>= 3.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
-
net6.0
- FlexQuery.NET (>= 3.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
-
net8.0
- FlexQuery.NET (>= 3.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
# 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:
```csharp
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:
```csharp
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
```bash
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.