DynamicQueryable.Extensions
1.6.2
This package has been deprecated. Please use FlexQuery.NET instead:
FlexQuery.NET
See the version list below for details.
dotnet add package DynamicQueryable.Extensions --version 1.6.2
NuGet\Install-Package DynamicQueryable.Extensions -Version 1.6.2
<PackageReference Include="DynamicQueryable.Extensions" Version="1.6.2" />
<PackageVersion Include="DynamicQueryable.Extensions" Version="1.6.2" />
<PackageReference Include="DynamicQueryable.Extensions" />
paket add DynamicQueryable.Extensions --version 1.6.2
#r "nuget: DynamicQueryable.Extensions, 1.6.2"
#:package DynamicQueryable.Extensions@1.6.2
#addin nuget:?package=DynamicQueryable.Extensions&version=1.6.2
#tool nuget:?package=DynamicQueryable.Extensions&version=1.6.2
DynamicQueryable
DynamicQueryable is a lightweight .NET library for applying dynamic filtering, sorting, paging, and projection to IQueryable (EF Core or any LINQ provider). It supports multiple query-string formats and produces EF Core-translatable expression trees.
Installation
dotnet add package DynamicQueryable.Extensions
Optional (async helpers for EF Core):
dotnet add package DynamicQueryable.Extensions.EFCore
Quick Start
Parse request query into QueryOptions
using DynamicQueryable.Parsers;
var options = QueryOptionsParser.Parse(Request.Query);
Apply to IQueryable
using DynamicQueryable.Extensions;
using Microsoft.EntityFrameworkCore;
[HttpGet]
public async Task<IActionResult> Get()
{
var options = QueryOptionsParser.Parse(Request.Query);
// Filter + sort + paging
var users = await _context.Users
.ApplyQueryOptions(options)
.ToListAsync();
// Projection (optional)
var projected = await _context.Users
.ApplyQueryOptions(options)
.ApplySelect(options)
.ToListAsync();
return Ok(new { users, projected });
}
Features
- Filtering: nested AND/OR groups, nested property paths, collection paths (EXISTS/
Any) - Sorting: multi-field ordering
- Paging:
page/pageSizeorskip/take(format-dependent) - Projection:
selectwith nested properties, plusinclude-style expansion - Query formats: Generic, JSON, DSL, JQL-lite, Syncfusion, Laravel Spatie
- EF Core friendly: expression-tree based, provider-translatable
Filtering & Query Formats
DynamicQueryable parses incoming query parameters into a unified model (QueryOptions, FilterGroup, FilterCondition). Operator behavior is consistent across formats.
Generic (indexed)
Simple filter
?filter[0].field=Name
&filter[0].operator=contains
&filter[0].value=john
Top-level logic (AND/OR)
?logic=or
&filter[0].field=City&filter[0].operator=eq&filter[0].value=Berlin
&filter[1].field=City&filter[1].operator=eq&filter[1].value=Paris
JSON (nested groups)
Advanced nested logic
?filter={
"logic":"and",
"filters":[
{
"logic":"or",
"filters":[
{"field":"City","operator":"eq","value":"London"},
{"field":"City","operator":"eq","value":"Berlin"}
]
},
{"field":"Age","operator":"between","value":"25,40"}
]
}
DSL (compact filter string)
Use & for AND (URL-encode as %26), | for OR, parentheses for grouping:
?filter=((city:eq:London|city:eq:Berlin)%26(age:between:25,40|status:eq:Pending))
JQL-lite (query)
Use SQL-like operators with AND / OR and parentheses for grouping:
?query=(name = "john" OR name = "doe") AND age >= 20
Supports nested property paths and quoted values:
?query=email = "ops@acmeretail.com" AND orders.number = "ORD-2026-0002" AND orders.items.quantity > 2
Supported JQL operators:
=!=>>=<<=CONTAINSIN (...)andNOT IN (...)
Unlike DSL/JSON malformed-input handling, invalid JQL syntax is surfaced as a parse exception to callers.
Syncfusion
?where[0][field]=Name
&where[0][operator]=contains
&where[0][value]=john
&sorted[0][name]=Age
&sorted[0][direction]=descending
&skip=0
&take=10
Use condition=and|or for top-level logic.
Laravel Spatie
Implicit AND (default Spatie behavior)
?filter[name]=Alice Johnson
&filter[status]=Active
Nested grouping
?filter[or][0][name]=john
&filter[or][1][name]=doe
Explicit operator support (extension)
?filter[name][operator]=contains
&filter[name][value]=john
(Works inside nested and/or groups as well.)
Operators
| Operator | Description | Example |
|---|---|---|
eq |
Equal | Name eq 'John' |
neq |
Not equal | Age neq 30 |
gt |
Greater than | Age gt 18 |
gte |
Greater than or equal | Age gte 18 |
lt |
Less than | Age lt 60 |
lte |
Less than or equal | Age lte 60 |
contains |
String contains | Name contains 'jo' |
startswith |
String starts with | Name startswith 'Jo' |
endswith |
String ends with | Name endswith 'hn' |
in |
Value exists in a list | Status in ['Active','Pending'] |
notin |
Value does not exist in list | Status notin ['Inactive'] |
between |
Inclusive range | Age between 18,60 |
isnull |
Is null | DeletedAt isnull |
notnull |
Is not null | DeletedAt notnull |
Nested & Collections
Nested property paths
Dot-notation works across filtering and projection:
?filter[0].field=Profile.Bio&filter[0].operator=contains&filter[0].value=dev
&select=Id,Profile.Bio
Collection paths (parent filtering)
Filtering on a collection navigation (e.g. Orders.Number) uses Any(...) / EXISTS semantics for the parent:
?filter[0].field=Orders.Number
&filter[0].operator=eq
&filter[0].value=SO-001
Conceptually:
x => x.Orders.Any(o => o.Number == "SO-001")
Filtered child collections (when selected)
When a request filters on a collection path and that collection is also projected, the returned child collection is filtered to match the same criteria (projection-based, EF Core translatable):
?filter[0].field=Orders.Number&filter[0].operator=eq&filter[0].value=SO-001
&select=Id,Orders.Number
Conceptually:
x => new {
x.Id,
Orders = x.Orders
.Where(o => o.Number == "SO-001")
.Select(o => new { o.Number })
.ToList()
}
API Methods
Apply filter/sort/paging
using DynamicQueryable.Extensions;
var options = QueryOptionsParser.Parse(Request.Query);
var query = _context.Users.AsQueryable()
.ApplyQueryOptions(options); // filter + sort + paging
var data = await query.ToListAsync();
Apply projection (select / include / JSON select tree)
var projected = await _context.Users
.ApplyQueryOptions(options)
.ApplySelect(options)
.ToListAsync(); // IQueryable<object>
Return results with metadata
var result = _context.Users.ToQueryResult(options);
// result.Data, result.TotalCount, result.Page, result.PageSize
Return projected results with metadata
var result = _context.Users.ToProjectedQueryResult(options);
// result.Data is List<object> shaped by Select/Includes/JSON select tree
EF Core async helpers (package: DynamicQueryable.Extensions.EFCore)
var result = await _context.Users.ToQueryResultAsync(options, cancellationToken);
var projected = await _context.Users.ToProjectedQueryResultAsync(options, cancellationToken);
ASP.NET Integration (optional)
You can parse directly in controllers/minimal APIs:
public abstract class BaseController : ControllerBase
{
protected QueryOptions Options => QueryOptionsParser.Parse(Request.Query);
}
License
MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net8.0
- Microsoft.Extensions.Primitives (>= 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.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 2.5.0 | 173 | 5/1/2026 | |
| 2.4.0 | 114 | 5/1/2026 | |
| 2.3.0 | 110 | 5/1/2026 | |
| 2.2.1 | 107 | 5/1/2026 | |
| 2.2.0 | 111 | 5/1/2026 | |
| 2.1.0 | 104 | 4/30/2026 | |
| 2.0.1 | 111 | 4/30/2026 | |
| 2.0.0 | 107 | 4/30/2026 | |
| 1.9.0 | 111 | 4/30/2026 | |
| 1.8.0 | 139 | 4/30/2026 | |
| 1.7.0 | 110 | 4/29/2026 | |
| 1.6.4 | 117 | 4/29/2026 | |
| 1.6.2 | 107 | 4/29/2026 | |
| 1.6.1 | 102 | 4/29/2026 | |
| 1.6.0 | 111 | 4/29/2026 | |
| 1.5.0 | 114 | 4/29/2026 |