How Queries Execute¶
The provider compiles LINQ expressions into PartiQL SELECT statements and executes them using DynamoDB's ExecuteStatement API, with any unsupported operators failing at translation time rather than silently falling back to client evaluation.
LINQ to PartiQL¶
When you execute a LINQ query, the provider runs it through a multi-stage compilation pipeline before any network call is made:
DynamoQueryableMethodTranslatingExpressionVisitorwalks the LINQ expression tree and builds aSelectExpression— an internal query model representing the projected columns,WHEREpredicate,ORDER BYorderings, and evaluation limit.DynamoQueryTranslationPostprocessorfinalizes theSelectExpression: it injects discriminator predicates for shared-table entity types and runs index selection analysis to determine whether a GSI or LSI should be used.DynamoQuerySqlGeneratorconverts theSelectExpressioninto a PartiQLSELECTstatement with positional?placeholders and a matchingAttributeValueparameter list.
FindAsync uses EF Core's normal entity-finder path. It checks the change tracker first; if the
entity is not tracked, EF Core produces a primary-key equality query that the provider translates
through the same async PartiQL execution pipeline.
var orders = await db.Orders
.Where(o => o.CustomerId == customerId && o.Status == "PENDING")
.OrderBy(o => o.CreatedAt)
.Select(o => new { o.OrderId, o.Total })
.ToListAsync(cancellationToken);
// Generated PartiQL:
// SELECT "OrderId", "Total"
// FROM "Orders"
// WHERE "CustomerId" = ? AND "Status" = ?
// ORDER BY "CreatedAt" ASC
Identifiers are always double-quoted in generated PartiQL, and quoted identifiers are case-sensitive. The parameter values are serialized as AttributeValue objects; no literal values appear in the SQL text.
The ExecuteStatement Model¶
All queries execute via the DynamoDB ExecuteStatement API — not via the Query or Scan SDK methods. ExecuteStatement accepts a PartiQL SELECT and a list of positional parameters, then returns a page of results and an optional continuation token.
Two fields on the request control result size:
Limit— an evaluation budget: the number of items DynamoDB reads before applying filter expressions. It is not a guarantee of how many matching items are returned. ALimit(25)query may return anywhere from 0 to 25 items depending on how many of the evaluated items satisfy theWHEREpredicate.NextToken— a continuation cursor returned by DynamoDB when the response was cut short by theLimitor by the 1 MB processed-data cap per request. The provider followsNextTokenautomatically for unbounded queries; for paged queries it exposes the token viaToPageAsync.
Note
DynamoDB stops processing a request at either the `Limit` item count or 1 MB of processed data, whichever comes first. A page can therefore contain zero matching items while still returning a non-null `NextToken` when many non-matching items were evaluated. Always check `NextToken == null` (not `Items.Count`) to determine end of results.
Client-Side vs Server-Side Evaluation¶
The provider has a strict server-side-first policy: if a LINQ operator cannot be translated to PartiQL, the translation fails with an InvalidOperationException at compile time. The provider never silently evaluates unsupported operators in-process against a full table scan.
The one sanctioned form of client-side evaluation is explicit: calling .AsAsyncEnumerable() marks the boundary between server execution and LINQ-to-objects. Any LINQ operators chained after AsAsyncEnumerable() run in-process against the result stream the server returned.
// Server evaluates the WHERE and Limit; client selects the first match.
var active = await db.Orders
.Where(o => o.CustomerId == customerId && o.IsActive)
.Limit(50)
.AsAsyncEnumerable()
.FirstOrDefaultAsync(cancellationToken);
Some projection shaping also runs client-side. Computed expressions in Select (string methods,
arithmetic, constructor calls) and nested complex-property materialization are applied by the
shaper lambda after the server returns the raw AttributeValue rows. This is expected behavior
and is documented per operator on the Projection page.
Debugging Generated PartiQL¶
Use EF Core's ToQueryString() to inspect generated PartiQL without sending a request to DynamoDB.
Parameterized queries include comment lines with positional parameter names (p0, p1, ...) and
formatted DynamoDB AttributeValue values before the PartiQL text.
var partiQl = db.Orders
.Where(o => o.CustomerId == customerId)
.ToQueryString();
// -- p0='CUSTOMER#123'
// SELECT "pk", "sk", "total"
// FROM "Orders"
// WHERE "CustomerId" = ?
ToQueryString() is for debugging only: it does not run scan warnings, log query execution events,
or execute ExecuteStatement.
Async Execution¶
All DynamoDB query execution is async. Attempting to enumerate results synchronously throws
InvalidOperationException. Find() can return an already-tracked entity without executing a
query; use FindAsync(), ToListAsync(), FirstOrDefaultAsync(), AsAsyncEnumerable(), or
ToPageAsync() when DynamoDB I/O is needed.