Generating dynamic LINQ expressions needs a bit of understanding on the IQueryable interface. Check out Matt Warren’s series of posts on implementing the IQueryable interface –> LINQ Links. The strong drive for this post is that everything is strongly typed; of course we have the Dynamic LINQ library that comes in the MSDN sample, but that comes with the overhead of generating strings to perform operations. In many cases, strongly typed usage will result in controlling the flow more accurately.
Let’s take a look at the extensions library that will be used for generating expressions on a dynamic data source that implements IQueryable/IEnumerable. In this post, we will look at generating an OrderBy() query with different parameters defined in the Queryable class. Normally, there are helper classes that have an implementation for generating LINQ expressions for IEnumerable and IQueryable interfaces. The Queryable class defines a wrapper thru which we can make calls to the IQueryProvider implemented for that source type (IQuerable/IEnumerable).
With our implementation we will (1) make our objects AsQueryable() and (2) call the appropriate method from the Queryable class that defines the method.
OrderBy() Query
The OrderBy query generates a simple sort comparer with the property name that is present in the underlying IQueryable source:
/// /// IQueryable expression for sorting in ascending. ///
/// /// public static IQueryable OrderBy(this IQueryable source, string propertyName) { var sourceType = source.GetObjectType(); ParameterExpression paramExpression = Expression.Parameter(sourceType, sourceType.Name); MemberExpression memExp = Expression.PropertyOrField(paramExpression, propertyName); LambdaExpression lambda = Expression.Lambda(memExp, paramExpression); return source.Provider.CreateQuery( Expression.Call( typeof(Queryable), “OrderBy”, new Type[] { source.ElementType, lambda.Body.Type }, source.Expression, lambda)); }
Taking a closer look at the functions:
Expression.Parameter – Defines the parameter on which the object is referred. Normally we would assign some parameter for the source in our LINQ expressions, say for the Northwind Orders table:
var orders = Orders.OrderBy( order => order.ShipCountry );
Like so, we can dynamically generate the above expression as:
var ordersQuerable = orders.AsQueryable();
var sortedOrders = ordersQueryable.OrderBy(“ShipCountry”);
You may want to perform multi-sorting on the underlying IEnumerable type. The other OrderBy-related functions that have similar implementation are:
- OrderByDescending
- ThenBy
- ThenByDescending
For building a big expression dynamically, all you have to do is loop thru the collection of sorted columns, and recursively build the expression by calling the OrderBy/OrderByDescending/ThenBy/ThenByDescending in some logical sequence.
Note: OrderByDescending/ThenByDescending will be generated only for an IOrderedQueryable instance. So you need to maintain some kind of an instance that holds IOrderedQueryable from the return set of OrderBy/ThenBy.
Helper Method
This retrieves the underlying object type for the IQueryable source.
private static Type GetObjectType(this IQueryable source) { var enumerable = source.GetEnumerator(); var hasItem = enumerable.MoveNext(); if (hasItem) { return enumerable.Current.GetType(); } return null; }
In the next posts, we will check out generating WHERE/Predicate expressions dynamically.