Dynamic LINQ Expressions – I

Generating dynamic LINQ expressions needs a bit of understanding on the IQueryable interface. Check out Matt’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 MSDN sample, but that comes with an over head of generating strings to perform operations. In many cases, strongly typed usage will result in controlling the flow more accurately.

Lets 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 OrderBy() query with different parameters defined in the Queryable class. Normally, there are helper classes that has 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 would go with making our objects AsQueryable().
  • 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 on the underlying IQueryable source,

/// <summary>
/// IQueryable expression for sorting in ascending.
/// </summary>
/// <param name="source"></param>
/// <param name="propertyName"></param>
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 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 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 gets 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 expression dynamically.

Hope this helps.

– Fahad

 
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: