How the engine works
A high-level tour of what sits between a fluent
From<T>()...Select(...)call and the rows you get back: the query command, the pipeline that turns it into SQL, the plan cache, execution and row materialization. For step-by-step usage see the Guide; for the caching rules see Plan cache and reuse.
Prerequisites: Quickstart · Entities and metadata.
The pipeline at a glance
Every query follows the same shape:
- A builder factory on the context creates the fluent builder:
ctx.From<TEntity>()returns anEntityBuilder<TEntity>; the fluent operators (Where,Join,Select, ...) accumulate into aQueryCommand<TResult>.Fromstarts a query — the other statement shapes have their own factories (see builder entry points). - A terminal (
ToListAsync,FirstAsync,AnyAsync, ...) drives preparation: the command is turned into a structuralQueryPlankey and looked up in the plan cache. - On a cache miss the query is prepared, translated to SQL text plus parameters, and paired with a compiled row mapper and a
DbCommand; the plan is stored back in the cache. - The command is executed against the database, and the
DbDataReaderis turned into result rows by the row mapper or streamed straight through.
| Piece | Responsibility |
|---|---|
IDataContext / provider DataContext |
Connection, metadata, dialect, command creation, and the builder factories — From* for queries, Create*Builder for DML, batch and CTAS. |
EntityBuilder<TEntity> |
The query builder: fluent LINQ surface (Where, Join, Select, ...), created by a From* factory. |
QueryCommand<TResult> |
The built query — source, projection, filters, joins, sorting, hints — and its terminals. |
QueryPreparer |
Turns the expression tree into prepared clause pieces and plan hashes (via expression visitors). |
QueryPlan / QueryPlanStore |
The structural plan key and the per-thread implicit plan cache. |
SqlBuilder + ISqlDialect |
Renders the dialect-specific SQL text and the parameter list. |
RowMapperFactory / RowMaterializer |
Compiles the row mapper (IDataRecord → entity / DTO). |
DbCommand (via DataContext.CreateCommand) |
The provider command carrying the SQL text and the bound parameters. |
QueryExecutor |
Runs the command and owns the ADO.NET reader. |
DbDataReader |
The ADO.NET reader over the result set. |
| Terminals | Every output shape: buffered collections, single rows, aggregates and scalars, streamed rows, JSON/CSV, and raw readers/streams. |
Builder entry points
Every statement starts at a factory on IDataContext that returns the builder for that statement shape. From is the query factory, not the only one:
| Entry point | Returns | Builds |
|---|---|---|
ctx.From<T>(), ctx.From<T>(o => ...) |
EntityBuilder<T> |
SELECT over a mapped entity, with per-source options |
ctx.From("table") |
EntityBuilder<TableAlias> |
SELECT over a raw table or CTE name |
ctx.FromSql(sql, parameters) |
EntityBuilder<TableAlias> |
SELECT over a derived-table SQL |
ctx.From(() => Db.MyTvf(...)) |
EntityBuilder<T> |
SELECT over a table-valued function |
ctx.From(query) / ctx.From(cte) / ctx.From(tempTable) / ctx.From(builder) |
EntityBuilder<TResult> (EntityBuilder<TableAlias> for a temporary table) |
SELECT over a subquery, a CTE, a lazy temporary table, or another builder |
ctx.CreateInsertBuilder<T>(), CreateBulkInsertBuilder<T>(), CreateUpdateBuilder<T>(), CreateDeleteBuilder<T>(), CreateMergeBuilder<T>(), CreateTruncateBuilder<T>() |
InsertBuilder<T>, BulkInsertBuilder<T>, UpdateBuilder<T>, DeleteBuilder<T>, MergeBuilder<T>, TruncateBuilder<T> |
DML statements |
ctx.CreateBatchBuilder() |
BatchBuilder |
several statements in one round trip |
builder.ToTable(name) / .ToTempTable(name) / .AsTempTable() |
CTAS command / TempTableSource<T> |
materialising a query into a table |
CreateQueryBuilder<T>() is an explicit alias of From<T>() and returns the same builder. The DML, batch and CTAS surfaces are shown in the Guide: INSERT, UPDATE, DELETE, MERGE, bulk insert, SQL batch, CREATE TABLE AS. The rest of this section follows the query (From) path.
Command execution path
The diagram traces the full path — from the fluent builder through the plan cache and SQL generation to execution and the row mapper:
Explicit Prepare()
The second diagram shows the explicit reuse path, where the query is compiled once into an IPreparedQueryCommand<TResult> and executed any number of times — the plan cache is not involved:
In this section
- Query pipeline: fluent to SQL — the command, preparation, the plan key and SQL generation.
- Execution and rows — running the command and shaping the result.
- Plan cache and reuse:
Prepare— the implicit cache and explicit prepared commands.