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> (this
	  IEnumerable<TSource> source,
	  Func<TSource,bool> predicate)

	public static IQueryable<TSource> Where<TSource> (this
	  IQueryable<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.