A colleague of mine recently called me out on the fact that I haven't blogged in … oh about a year and a half. Well it’s 2010 now and resolution season is in full swing so here’s my attempt at getting back on the ball (no promises though).

In a recent post Scott Hanselman described writing custom filters for ASP.NET Dynamic Data. Scott provides a nice overview of the Dynamic Data architecture and then gets his hands dirty with some custom filters using the advanced capabilities available in Dynamic Data Futures. However, he soon realizes that writing custom late-bound LINQ expressions is definitely not a trifle.

I started thinking about how this experience could be improved and so started writing some code. Things were going great and I was well on my way towards providing the “magic” code that would make Scott’s task that much easier when I started getting this déjà vu feeling that I had already seen something very similar. I scratched my head a bit and then remembered a long-lost sample for dynamically building LINQ queries written back when the original Visual Studio 2008 shipped.

It’s available as a download but it also comes bundled with your VS (both 2008 and 2010) installation under the following path in your VS installation directory:

Samples\1033\CSharpSamples.zip\LinqSamples\DynamicQuery\DynamicQuery

This sample implements a subset of the LINQ extension methods in a late-bound, string-based manner. So for example (using Scott’s model classes) instead of writing this:

IQueryable<Brick> bricks; // strongly-typed collection of bricks
var result = bricks.Select(p => p.Year).Distinct().OrderBy(i => i);

you can write this “magic” code:

using System.Linq.Dynamic; // you need to include this namespace
                           // for the extension methods to kick in

IQueryable bricks; // weakly-typed collection of bricks
var result = bricks.Select("Year").Distinct().OrderBy("it");

DynamicQueryable is quite powerful and includes the following

  • Dynamic string-based querying of any LINQ provider (late-bound versions of Where, Select, OrderBy, Take, Skip, GroupBy, Any, and Count extension methods)
  • String-based mini expression language (like the “it” identifier in the sample above), including complex conditional statements and all operators
  • Dynamic creation of classes for projections

The only custom code that I had to write to support Scott’s scenario was the Distinct method, which is missing from what’s provided. Fortunately this was not that difficult:

public static class DynamicQueryableExtras {
    public static IQueryable Distinct(this IQueryable q) {
        var call = Expression.Call(typeof(Queryable), 
                                   "Distinct",
                                   new Type[] { q.ElementType },
                                   q.Expression);
        return q.Provider.CreateQuery(call);
    }
}

Other missing LINQ APIs could be added quite easily too.

Once I had the Distinct extension method it was easy to rewrite Scott’s code:

protected void Page_Init(object sender, EventArgs e) {
    var items = Column.Table.GetQuery();
    var entityParam = Expression.Parameter(Column.Table.EntityType, "row");

    // row => row.Property
    var columnLambda = Expression.Lambda(Expression.Property(entityParam, Column.EntityTypeProperty), entityParam);

    // Items.Select(row => row.Property)
    var selectCall = Expression.Call(typeof(Queryable),
                                     "Select",
                                     new Type[] { items.ElementType, columnLambda.Body.Type },
                                     items.Expression,
                                     columnLambda);

    // Items.Select(row => row.Property).Distinct
    var distinctCall = Expression.Call(typeof(Queryable),
                                       "Distinct",
                                       new Type[] { Column.EntityTypeProperty.PropertyType },
                                       selectCall);

    // colvalue => colvalue
    var sortParam = Expression.Parameter(Column.EntityTypeProperty.PropertyType, "sortValue");
    var columnResultLambda = Expression.Lambda(sortParam, sortParam);

    // Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
    var ordercall = Expression.Call(typeof(Queryable),
                                    "OrderBy",
                                    new Type[] { Column.EntityTypeProperty.PropertyType, columnResultLambda.Body.Type },
                                    distinctCall,
                                    columnResultLambda);

    var result = items.Provider.CreateQuery(ordercall);

    foreach (var item in result) {
        if (item != null) DropDownList1.Items.Add(item.ToString());
    }
}

as:

protected void Page_Init(object sender, EventArgs e) {
    var items = Column.Table.GetQuery();

    var result = items.Select(Column.EntityTypeProperty.Name)
                      .Distinct()
                      .OrderBy("it");

    foreach (var item in result) {
        if (item != null) DropDownList1.Items.Add(item.ToString());
    }
}

Much simpler, wouldn’t you agree?

I hope this technique will save you time trying to figure out how to dynamically build LINQ expressions. The sample contains a detailed document describing all of the APIs and the features available in the expression language. You should definitely check it out because it is very powerful. Oh, and if this also looks familiar to you, that’s because it’s almost the same as the querying features in LinqDataSource.