Query syntax and method syntax
The two spellings of LINQ, how the compiler rewrites one into the other, and which to reach for in a given situation.
One query, two spellings
LINQ is a set of extension methods on IEnumerable<T> and IQueryable<T>. Query syntax is the SQL-like form the C# compiler translates into those methods; method syntax is the direct call chain. They produce identical results.
// query syntax
var query =
from o in orders
where o.Total > 100
orderby o.Total descending
select new { o.Id, o.Customer, o.Total };
// method syntax - exactly what the compiler emits for the above
var method = orders
.Where(o => o.Total > 100)
.OrderByDescending(o => o.Total)
.Select(o => new { o.Id, o.Customer, o.Total });| Clause | Equivalent method |
|---|---|
from x in src | The source itself |
where | Where |
select | Select |
orderby | OrderBy / OrderByDescending / ThenBy |
join ... on ... equals ... | Join |
group ... by | GroupBy |
let | Select introducing an intermediate value |
into | Feeds the result of one clause into a continuation |
- Query syntax must start with
fromand end withselectorgroup. - Query syntax supports one
let,joinandgroupper clause naturally; anything beyond becomes nested and less readable. - A query that only calls
Whereor onlySelectis shorter in method syntax.
Joins, let and grouping
// inner join: customers with at least one order
var report =
from c in customers
join o in orders on c.Id equals o.CustomerId
let isLarge = o.Total > 500
orderby c.Name, o.Total descending
select new { c.Name, o.Id, o.Total, isLarge };
// group join: every customer, with their orders (possibly none)
var withOrders =
from c in customers
join o in orders on c.Id equals o.CustomerId into ordersForCustomer
select new
{
c.Name,
Count = ordersForCustomer.Count(),
Spend = ordersForCustomer.Sum(x => x.Total)
};// group by one key
var byCountry = orders
.GroupBy(o => o.Country)
.Select(g => new
{
Country = g.Key,
Orders = g.Count(),
Revenue = g.Sum(o => o.Total)
})
.OrderByDescending(x => x.Revenue)
.ToList();
// grouping by a composite key and shaping each group
var byMonth = orders
.GroupBy(o => new { o.Country, Month = o.Placed.Month })
.Select(g => new
{
g.Key.Country,
g.Key.Month,
Top = g.OrderByDescending(o => o.Total).First().Id
});💡
join ... into is a group join, not a left outer join by accident: it produces one row per left element with a sequence of matches. If you want a flat left join, group join then SelectMany with DefaultIfEmpty().Choosing a form
// left outer join in method syntax
var leftJoin = customers
.GroupJoin(orders, c => c.Id, o => o.CustomerId,
(c, os) => new { Customer = c, Orders = os })
.SelectMany(
x => x.Orders.DefaultIfEmpty(),
(x, o) => new { x.Customer.Name, OrderId = o?.Id, Total = o?.Total ?? 0 });
// the same outer join is clearer in query syntax
var leftJoinQuery =
from c in customers
join o in orders on c.Id equals o.CustomerId into os
from o in os.DefaultIfEmpty()
select new { c.Name, OrderId = o?.Id, Total = o?.Total ?? 0 };| Situation | Prefer |
|---|---|
| Multi-source join with filters | Query syntax |
Single chain of Where / Select | Method syntax |
| Custom operators or third-party extensions | Method syntax (query syntax cannot call them) |
| Mixing query result into a larger expression | Method syntax |
| Complex grouping and shaping | Query syntax |
The rule that holds up in review: use query syntax where the structure is relational and method syntax everywhere else. Do not mix both inside one expression — a reader has to re-parse the shape twice.
FAQ
Is one form faster than the other?
No. Query syntax is translated to the same method calls at compile time, so the IL is equivalent. Choose on readability alone.
Why does my query syntax not compile after I add a custom method?
Query syntax only understands a fixed set of clauses. Insert the custom call with parentheses —
(from x in src select x).MyExtension() — or switch that query to method syntax.Related
Common LINQ operators Deferred execution and querying a database
Last refreshed 2026-09-18.