Skip to content

Supported Operators

This page is the authoritative reference for which LINQ operators translate to PartiQL server-side, which are evaluated client-side, and which are unsupported.

Filtering Operators

LINQ Operator PartiQL Translation Notes
Where WHERE Boolean properties normalized to = true
==, !=, scalar Equals =, <> Works on all scalar types; supports single-argument prop.Equals(value), string.Equals(value, StringComparison.Ordinal), static string.Equals, and object.Equals(prop, value) for compatible scalar operands; complex property-to-property and parameter equality translate for map attributes; comparers and non-ordinal StringComparison overloads are unsupported
<, <=, >, >= <, <=, >, >= Numeric and date/time properties only; C# does not define these operators on string — use string.Compare or CompareTo instead
string.Compare(a, b) > 0 (any comparison against 0) a > b Required for string range comparisons; works with ==, !=, <, <=, >, >= against 0 only. Exact comparisons against 1 or -1 are not translated because .NET only guarantees negative/zero/positive results
a.CompareTo(b) > 0 (any comparison against 0) a > b Same as above; 0 < a.CompareTo(b) form also supported (operands mirrored). Compare only against 0
== null IS NULL OR IS MISSING Covers both DynamoDB null representations, including nested complex-property paths such as x.Profile.Address == null
!= null IS NOT NULL AND IS NOT MISSING De Morgan inverse of == null; also works on nested complex-property paths
nullable scalar/complex HasValue IS NOT NULL AND IS NOT MISSING Checks that the scalar attribute or complex map attribute exists and is not NULL
nullable complex .Value.Property nested attribute path Accesses scalar members inside nullable complex value objects, e.g. x.Profile.Value.ZipCode"Profile"."ZipCode"
EF.Functions.IsNull(prop) prop IS NULL Explicit: NULL type only
EF.Functions.IsNotNull(prop) prop IS NOT NULL Explicit: not NULL type
EF.Functions.IsMissing(prop) prop IS MISSING Explicit: attribute absent from item
EF.Functions.IsNotMissing(prop) prop IS NOT MISSING Explicit: attribute present
!expr NOT (expr) Operand always parenthesized
prop >= a && prop <= b prop BETWEEN a AND b Both bounds must be inclusive (>= and <=)
string.Contains(s) contains(attr, ?) Case-sensitive substring; supports string and StringComparison.Ordinal overloads; char, culture, and non-ordinal comparison overloads are unsupported
entity.Collection.Contains(value) contains(attr, ?) Native DynamoDB list/set primitive collection membership; scalar value-converted collections are not translated
entity.Collection.Any() / entity.Bytes.Any() size(attr) > 0 Native DynamoDB primitive collection and binary (byte[]) attributes only; predicate Any(...) remains unsupported except inline finite collection rewrites
entity.Collection.Count, .Count(), .Length; entity.Bytes.Length size(attr) Native DynamoDB primitive collection length/count and binary byte length; predicate Count(...) and query-level aggregate Count remain unsupported
entity.Collection[constant], .ElementAt(constant) attr[index] Direct primitive LIST element access with a constant numeric index only; dynamic indexes, filtering, ordering, or paging inside list elements remain unsupported
entity.Collection.First(), .FirstOrDefault() attr[0] Direct first-element access on primitive LIST attributes only; translates as constant index 0. General sequence First* terminal rules still apply to root queries
string.StartsWith(s) begins_with(attr, ?) Case-sensitive prefix; supports string and StringComparison.Ordinal overloads; char, culture, and non-ordinal comparison overloads are unsupported
string.Length size(attr) DynamoDB size semantics; for strings, use with care when non-ASCII text matters
string.IsNullOrEmpty(s) attr IS NULL OR attr IS MISSING OR attr = '' Matches DynamoDB NULL, missing attributes, or empty string
entity.Bytes.SequenceEqual(bytes) attr = ? Binary (byte[]) equality; binary literals are parameterized because DynamoDB PartiQL has no inline binary literal syntax
collection.Contains(prop) prop IN [?, ...] In-memory collection membership; max 50 PK values, 100 non-key values. Nullable item comparisons are supported when element mapping is known
new[] { a, b }.Any(x => x == prop) (a = prop) OR (b = prop) Inline finite collection predicate rewrite only; no server aggregate or subquery is emitted
new[] { a, b }.All(x => x != prop) (a <> prop) AND (b <> prop) Inline finite collection predicate rewrite only; useful for negated contains-style predicates
OfType<TDerived>() discriminator predicate TPH inheritance only; filters by concrete discriminator values for the requested derived type. x is TDerived translates when the target type can be expressed as discriminator values. x.GetType() == typeof(TConcrete) translates only for exact concrete mapped entity types.

Projection Operators

LINQ Operator PartiQL Translation Notes
Select Explicit column list SELECT * is never emitted; computed expressions and nested complex-property shaping evaluate client-side. Primitive collection properties can be projected directly

Ordering Operators

LINQ Operator PartiQL Translation Notes
OrderBy / OrderByDescending ORDER BY col ASC\|DESC Only partition key and sort key columns are valid
ThenBy / ThenByDescending Additional ORDER BY column For multi-partition queries, partition key must be the first column

Terminal Operators

Terminal operators execute the query and return results. The provider supports the following terminals:

LINQ Operator Behavior Notes
ToListAsync() Fetches all pages; returns List<T> Provider follows NextToken until exhausted
AsAsyncEnumerable() Streams results as IAsyncEnumerable<T> Marks the explicit client-side evaluation boundary; LINQ applied after this runs in-process
ToPageAsync(limit, token) Single DynamoDB request; returns DynamoPage<T> DynamoDB-specific; use for cursor-based pagination
First / FirstOrDefault Implicit Limit=1; single request Key-only safe path by default; AsUnsafeFilteredQuery() bypasses safety validation but can miss later matching items
Single / SingleOrDefault Implicit Limit=2; single request Key-condition-only; allows PK equality or PK IN; shared-table discriminator queries need base-table single-item lookup

Primary-Key Lookup

Use FindAsync when you have the full DynamoDB table key and want one entity by primary key. It checks the EF Core change tracker first. If the entity is not already tracked, the provider executes a base-table key-equality PartiQL query with ExecuteStatementRequest.Limit = 1.

// Partition-key-only table
var customer = await context.Customers.FindAsync(["CUSTOMER#123"], ct);

// Composite partition + sort key table; pass values in PK, SK order
var order = await context.Orders.FindAsync(["CUSTOMER#123", "ORDER#456"], ct);

FindAsync returns null when no item exists. It targets the base table and does not use secondary indexes or automatic index selection; use normal LINQ with .WithIndex(...) or automatic selection for secondary-index lookups. Synchronous Find can return an already-tracked entity, but throws if it needs to query DynamoDB.

DynamoDB-Specific Extensions

The following extension methods are unique to this provider and have no standard LINQ equivalent. They compose with the query before a terminal operator is called.

Extension Behavior Notes
Limit(n) Sets ExecuteStatementRequest.Limit — evaluation budget DynamoDB reads up to n items then applies filters; returned count is 0..n. Last call wins. See Ordering and Limiting
WithNextToken(token) Seeds the first request with a saved continuation cursor Resumes a previous query from a known position. See Pagination
WithConsistentRead() Requests strongly consistent reads for this query Sets ExecuteStatementRequest.ConsistentRead = true for base-table and LSI reads. Throws if the finalized source is a GSI because DynamoDB does not support strong consistency on GSIs. WithConsistentRead(false) explicitly uses eventually consistent reads for one query
WithIndex(name) Routes the query to a named GSI or LSI Emits FROM "Table"."Index" in PartiQL. See Index Selection
WithoutIndex() Forces base-table execution; suppresses automatic index selection Emits diagnostic DYNAMO_IDX006. Cannot combine with WithIndex(...)
AsUnsafeFilteredQuery() Bypasses First* safety validation for this query Does not disable scan-like query protection, does not bypass Single* validation, and does not change terminal execution semantics. Use only for tests or controlled legacy code

Unsupported Operators

The following operators are not supported and throw InvalidOperationException at translation time. The provider does not silently fall back to in-process evaluation.

Category Operators Reason
Element operators Any(predicate), All except supported inline finite collection predicate rewrites General server-side element operators are unsupported; primitive collection Any() translates to size(attr) > 0
Offset / paging Skip, Take, root/query-sequence ElementAt, ElementAtOrDefault DynamoDB has no offset semantics; direct primitive LIST attribute ElementAt(constant) translates to list indexing
Reverse traversal Last, LastOrDefault, Reverse Requires reverse index traversal, not currently implemented
Deduplication Distinct SELECT DISTINCT is not supported in DynamoDB PartiQL
Aggregation Count, LongCount, Sum, Average, Min, Max No query aggregate functions in DynamoDB PartiQL; primitive collection count/length translates to size(attr)
Grouping GroupBy GROUP BY is not supported
Joins Join, GroupJoin, SelectMany, LeftJoin, RightJoin, DefaultIfEmpty DynamoDB does not support cross-item joins
Set operations Union, Concat, Except, Intersect Not supported
Conditional filtering SkipWhile, TakeWhile Not supported
Type casting Cast<T> Not supported; use TPH inheritance queries with OfType<TDerived>() for type filtering

Scalar Type Support

All scalar entity properties must map to a DynamoDB attribute type. Types without a native wire representation use built-in EF Core value converters.

.NET Type DynamoDB Attribute Type Wire Format
string S
bool BOOL
byte, sbyte, short, int, long N Numeric string
ushort, uint, ulong N Numeric string
float, double, decimal N Numeric string
byte[] B Binary
Guid S "D" format, e.g. "550e8400-e29b-41d4-a716-446655440000"
DateTime S ISO 8601 round-trip ("O")
DateTimeOffset S ISO 8601 round-trip ("O")
DateOnly S "yyyy-MM-dd", e.g. "2026-04-19"
TimeOnly S "HH:mm:ss" (whole-second) or "o" (sub-second)
TimeSpan S Constant ("c") format, e.g. "01:30:00"
Enum N Underlying numeric value (string names require a converter)

Nullable variants of all types above are supported. Numeric comparisons use DynamoDB's single N wire type, so promotions to int, such as short to int, still bind as DynamoDB numbers. Custom types can be mapped using EF Core value converters; query parameters and constants use the property mapping so converters apply consistently.

Value-converted enums compare using the converter provider type. For example, an enum mapped with .HasConversion<string>() binds parameters as DynamoDB strings. Numeric casts of value-converted enums, such as (int)entity.Status == value, are not translated for parameter comparisons because the DynamoDB attribute stores the converted provider value. Compare enum values directly, or map the enum numerically if numeric comparisons are required.

See also