Building Query Expressions
So far, when we’ve needed to dynamically compose queries, we’ve done so by conditionally chaining query operators. Although this is adequate in many scenarios, sometimes you need to work at a more granular level and dynamically compose the lambda expressions that feed the operators.
In this section, we’ll assume the following Product
class:
[Table] public partial class Product { [Column(IsPrimaryKey=true)] public int ID; [Column] public string Description; [Column] public bool Discontinued; [Column] public DateTime LastSale; }
Delegates Versus Expression Trees
Recall that:
Local queries, which use
Enumerable
operators, take delegates.Interpreted queries, which use
Queryable
operators, take expression trees.
We can see this by comparing the signature of the Where
operator in Enumerable
and Queryable
:
public static IEnumerable<TSource> Where<TSource> (thisIEnumerable
<TSource> source, Func<TSource,bool> predicate) public static IQueryable<TSource> Where<TSource> (thisIQueryable
<TSource> source,Expression
<Func<TSource,bool>> predicate)
When embedded within a query, a lambda expression looks
identical whether it binds to Enumerable
’s operators or Queryable
’s operators:
IEnumerable<Product> q1 = localProducts.Where (p => !p.Discontinued
); IQueryable<Product> q2 = sqlProducts.Where (p => !p.Discontinued
);
When you assign a lambda expression to an intermediate variable,
however, you must be explicit about whether to resolve to a delegate
(i.e., Func<>
) or an expression ...
Get LINQ Pocket Reference now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.