Queries
db.Query() provides a fluent interface for filtering, sorting, pagination, aggregation, and query-scoped writes over the full dataset. Every db.Query() call is a full scan — use QueryViaIndex when an index lookup is more appropriate.
Methods fall into two categories:
- Builder methods — shape the working set and chain together:
Where,OrderBy,Skip,Limit - Terminal methods — execute and return a result:
ToArray,Select,SelectDistinct,Sum,Min,Max,Avg,Update,Delete
GroupBy is a special case — it transitions into a grouped query context. See GroupBy.
Builder Methods
| Method | Signature | Description |
|---|---|---|
Where | Where(Func<T, bool>) | Filter records by predicate |
OrderBy | OrderBy(Comparison<T>) | Sort using a comparison delegate |
Skip | Skip(int) | Skip the first N records |
Limit | Limit(int) | Cap the result set at N records |
GroupBy | GroupBy<TKey>(Func<T, TKey>) | Group records by key — see GroupBy |
OrderBy takes a Comparison<T> delegate — the same contract as Array.Sort. Ascending compares p1 to p2; descending reverses the arguments and compares p2 to p1.
// Filter, sort, paginate
Person[] page = db.Query()
.Where(p => p.IsAdult)
.OrderBy((p1, p2) => p1.BirthDate.CompareTo(p2.BirthDate))
.Skip(5)
.Limit(5)
.ToArray();Materialization
// Materialize all matching records as T[]
Person[] kids = db.Query().Where(p => !p.IsAdult).ToArray();
Person[] adults = db.Query().Where(p => p.IsAdult).ToArray();
// Project to a different type — returns string[]
string[] names = db.Query()
.Where(p => p.Ssn != string.Empty)
.Select(p => $"{p.LastName}, {p.FirstName}");
// Project to distinct values, sorted — returns string[]
string[] distinctLastNames = db.Query()
.Where(p => p.Ssn != string.Empty)
.OrderBy((p1, p2) => p1.LastName.CompareTo(p2.LastName))
.SelectDistinct(p => p.LastName);Select and SelectDistinct skip the deep copy when the projected type is a string or value type — only reference-type projections incur the clone cost.
Aggregates
All aggregates return 0 or default(Y) when the result set is empty.
// Sum
decimal totalKidNetWorth = db.Query().Where(p => !p.IsAdult).Sum(p => p.NetWorth);
decimal totalAdultNetWorth = db.Query().Where(p => p.IsAdult).Sum(p => p.NetWorth);
// Min / Max
decimal minKidNetWorth = db.Query().Where(p => !p.IsAdult).Min(p => p.NetWorth);
decimal maxAdultNetWorth = db.Query().Where(p => p.IsAdult).Max(p => p.NetWorth);
// Avg — combine multiple Where conditions with &&
decimal avgKidNetWorth = db.Query().Where(p => !p.IsAdult).Avg(p => p.NetWorth);
decimal avgHighCreditAdultWorth = db.Query()
.Where(p => p.IsAdult && p.CreditScore >= 700)
.Avg(p => p.NetWorth);Sum is overloaded for the standard numeric types and returns the same type as the selector. Min and Max are generic — they return whatever type the selector projects to.
| Selector type | Sum returns | Avg returns |
|---|---|---|
int | int | double |
long | long | double |
float | float | float |
double | double | double |
decimal | decimal | decimal |
Query-Scoped Writes
Query-scoped Update and Delete apply one action across every record matching the query and return the count affected. They operate identically to their Basic Operations counterparts and remain full scans.
// Increase credit score by 10 for high-net-worth adults — returns count updated
int updated = db.Query()
.Where(p => p.IsAdult && p.CreditScore > 0 && p.NetWorth >= 100_000)
.Update(p => p.CreditScore = p.CreditScore + 10);
// Delete the 2 adults with the lowest credit scores — returns count deleted
int deleted = db.Query()
.Where(p => p.IsAdult)
.OrderBy((p1, p2) => p1.CreditScore.CompareTo(p2.CreditScore))
.Limit(2)
.Delete();GroupBy
GroupBy transitions into a grouped query context and exposes two operations:
Having— filter groups by predicate; chainableSelect— terminal; projects each group to a result and returnsTResult[]
// Sum net worth per family (group by last name)
(string lastName, decimal netWorth)[] familyWorth = db.Query()
.GroupBy(p => p.LastName)
.Select(g => (g.Key, g.Sum(p => p.NetWorth)));
// Same query, but only families with more than one member
(string lastName, decimal netWorth)[] multiMemberFamilies = db.Query()
.GroupBy(p => p.LastName)
.Having(g => g.Count() > 1)
.Select(g => (g.Key, g.Sum(p => p.NetWorth)));The Select lambda receives a standard IGrouping<TKey, T> — all standard LINQ operations are applicable.