Configuration
FlexQuery is configured at three levels, and every level has one job: the more general one supplies defaults, the more specific one overrides them. Understanding this layering — and the immutability rule that guards it — is the difference between predictable behavior and order-of-initialization bugs.
Global (FlexQueryCore) <- application-wide defaults, set once
|- Provider (EFCore/Dapper) <- provider behavior (no-tracking, model, timeout)
`- Per request <- per-call overrides (governance, limits, syntax)Global options
FlexQueryCore.Configure runs once at startup, before any query:
using FlexQuery.NET;
var builder = WebApplication.CreateBuilder(args);
FlexQueryCore.Configure(options =>
{
options.DefaultQuerySyntax = QuerySyntax.NativeDsl;
options.DefaultPageSize = 20;
options.MaxPageSize = 1000;
options.IncludeTotalCount = true;
options.StrictFieldValidation = true;
options.MaxFieldDepth = 5;
});| Property | Type | Default | Description |
|---|---|---|---|
DefaultQuerySyntax | QuerySyntax | NativeDsl | Syntax used when no per-request syntax is supplied. |
DefaultPageSize | int | 20 | Page size when the client omits one. |
MaxPageSize | int | 1000 | Maximum page size a client may request. |
IncludeTotalCount | bool | true | Compute total counts by default. |
StrictFieldValidation | bool | true | Throw on unauthorized field access. |
MaxFieldDepth | int | 5 | Maximum nested field-path depth. |
Global type maps
FlexQueryOptions.CreateMap registers application-level entity to DTO maps that every typed
execution reuses:
FlexQueryCore.Configure(options =>
{
options.CreateMap<Customer, CustomerResponse>()
.ForMember(dto => dto.CustomerFullName, entity => entity.CustomerName);
options.CreateMap<Order, OrderResponse>();
});Per-query CreateMap registrations take precedence over global maps. See
Typed DTO Projection.
Provider options
EF Core
FlexQueryEFCore.Configure(options =>
{
options.UseNoTracking = true;
});FlexQueryEFCore.Setup() (no delegate) only registers the EF Core-specific operator
handlers, such as like. UseNoTracking defaults execution to no-tracking; each call can
override it (opt.UseNoTracking = false).
Dapper
Dapper needs a model — there is no DbContext to reflect over:
using FlexQuery.NET.Dapper.Configuration;
FlexQueryDapper.Configure(options =>
{
options.CommandTimeout = 30;
options.Model.Entity<Customer>()
.ToTable("Customers")
.HasKey(c => c.Id)
.HasMany(c => c.Orders)
.HasForeignKey("CustomerId");
});Relationship configuration can also be grouped per entity in an
IEntityTypeConfiguration<T> class and applied with ApplyConfiguration /
ApplyConfigurationsFromAssembly. Entity types with standard naming and
[Table]/[Column]/[Key] attributes need no explicit configuration at all —
conventions fill in the gaps.
The SQL dialect is auto-detected from the DbConnection type at runtime. See
Dapper for the full mapping API.
Per-request overrides
Every execution method accepts an optional Action<...Options> delegate that wins over
global/provider values:
var result = await db.Customers
.FlexQueryAsync(parameters, opt =>
{
opt.MaxPageSize = 50; // tighter ceiling
opt.AllowedFields = ["Id", "FirstName", "Email"]; // endpoint surface
opt.QuerySyntax = QuerySyntax.Fql; // force a syntax
opt.UseNoTracking = false; // opt out of no-tracking (EF)
}, cancellationToken);Typical per-request settings: governance sets (see Security), paging limits, query syntax, field mappings, per-query type maps, and the diagnostics listener.
Precedence rules
| Setting | Global | Provider | Per request |
|---|---|---|---|
| Default query syntax | Yes | — | Yes (overrides global) |
| Page size defaults / limits | Yes | — | Yes (overrides global) |
| Validation strictness & field depth | Yes (baseline) | — | Yes (overrides) |
| Field governance sets (Allowed/Blocked/…) | — | — | Yes (per request) |
| No-tracking behavior | — | Yes (default) | Yes (per call) |
Dapper model (statics/FlexQueryDapper.Configure) | — | Yes | attributes per query |
| Type maps | Yes (global maps via FlexQueryOptions.CreateMap) | — | Yes (per-query wins) |