Merging Expression Trees to Reuse in Linq Queries

Reusing parts of LINQ queries is easily done by chaining methods returning IQueryable. Unfortunately that doesn’t cover some senarios like reusing member initialization lists. To handle such a situation I wrote a Merge extension method for select expressions.

For this post we’ll load the data required for a list of cars and a detail view for one car. When loading the details, more fields are required than when just loading the list. With the merging helper method we can reuse the query for the basic list and just extend it with the added properties.

The basic info for the list view is held in a CarBasicInfo DTO class. The data for the detail view is held in a CarExtendedInfo class which is derived from the CarBasicInfo class. A helper method contains the Select() call to map Car entities to the basic DTO. Now the Merge extension method can be used to merge an expression with the initialization of the additional fields for the extended DTO with the existing helper method for the basic fields.

private Expression<Func<Car, CarBasicInfo>> basicSelect =
    c => new CarBasicInfo
    {
        CarId = c.CarId,
        RegistrationNumber = c.RegistrationNumber
    };
 
var car = ctx.Cars.Select(basicSelect.Merge(c => new CarExtendedInfo
{
    Color = c.Color,
    BrandName = c.Brand.Name
})).Single(c => c.RegistrationNumber == "ABC123");

The RegistrationNumber field is not mentioned in the init list – it is populated by the basic select in the SelectBasicInfo helper method. To accomplish this some (non trivial) rewriting of expression trees is in the Merge method.

Traversing Expression Trees

The Expression<T> data type which was introduced together with LINQ is interesting. When a Func<TResult> is wrapped in an Expression<T> the code is no longer completely compiled, instead it is preserved as an expression tree that can be traversed during runtime. This is what the method ExpressionHelper.GetExpressionText() that I used in my last post Type Safe SelectList Factory utilizes. In that post I used a simple lambda to select a property of a class.

IEnumerable = GetPeople();
SelectList selectList = 
  people.ToSelectList(people, p => p.Id, p => p.FullName);

To check how this works under the hood, I inspected the lambda object in a debugger and made a graph overview with the excellent dot tool.

Software Development is a Job – Coding is a Passion

I'm Anders Abel, a systems architect and developer working for Kentor in Stockholm, Sweden.

profile for Anders Abel at Stack Overflow, Q&A for professional and enthusiast programmers

The complete code for all posts is available on GitHub.

Popular Posts

Archives

Series

Powered by WordPress with the Passion for Coding theme.