Wednesday, July 2, 2014

Writing a Very Basic Dynamic Query using Expression Trees

In this post, let’s see how we can write a very simple query using expression trees which gets generated at the run time. If you are not aware of Expression Trees, let me quickly give you an introduction.

Expression trees represent code in a tree-like data structure, where each node is an expression. The nicest thing about expression trees is, in the run time you can compile and run the code represented by expression trees. Because of this nature you can do many things. One example would be dynamic queries, which means based on your conditions defined in the code, you can create your query in the run time.

This is the query which I am going to construct with expression trees.
employees.Where(e => e.Country == "Sri Lanka");
Pretty simple right? Yes it is a very basic query, the reason for me to use this query as the model is because the more simpler the query, I will need to have a simple expression. But I believe, that simple expression tree is more than enough to get you start writing complex expression trees.

So Let’s get into action. I have following simple model which is “Employee”.
public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
 
    public static List<Employee> GetEmployees()
    {
        return new List<Employee>()
        {
            new Employee(){EmployeeId=1,Name="Jaliya Udagedara", Country="Sri Lanka"},
            new Employee(){EmployeeId=2,Name="John Smith", Country="United States"},
            new Employee(){EmployeeId=3,Name="Jane Smith", Country="United States"},
        };
    }
}
I don’t think I need to explain every line of code up there. In my Main method, I have the following code.
static void Main(string[] args)
{
    List<Employee> employees = Employee.GetEmployees();
    var filteredEmployees = employees.Where(e => e.Country == "Sri Lanka");

    foreach (var item in filteredEmployees)
    {
        Console.WriteLine(item.Name);
    }
}
Here Where extension method expects a Func<Employee,bool> predicate.
image
Func<Employee,bool> predicate
If you are wondering what Func is read one of my previous posts which explains Action, Func<TResult> and Predicate<T> Delegate.

So if I run this, I am getting the expected output, and that’s of course no magic.
image
Output
Now let’s see how we can write expression tree which generates the same query.

First step is to create the expression tree that represents the parameter to the predicate which is “e”.
ParameterExpression pe = Expression.Parameter(typeof(Employee), "e");

As you know every expression has two sides, left and right. And in the middle there will be an operator. Now let’s write the expression which points to the left side of the expression.
Expression left = Expression.Property(pe, typeof(Employee).GetProperty("Country"));

Now above two expressions are responsible for composing the following.
e=>e.Country

Let’s move into the right side of the expression. In the right hand side, I have a value.
Expression right = Expression.Constant("Sri Lanka");

Now what we need to do is perform some operation on these left and right expressions. Here what we need is the equality operator (==).
Expression expression = Expression.Equal(left, right);

Ok, now all done. Final step is, compile the expression tree into executable code.
var lambda = Expression.Lambda<Func<Employee, bool>>(expression, pe).Compile();

The compiled lambda expression is as follows.
e => e.Country == "Sri Lanka"

Now I can pass the compiled lambda expression to Where extension method.
var filteredEmployees = employees.Where(lambda);

That’s all. So following is how it look likes when all above parts comes together.
ParameterExpression pe = Expression.Parameter(typeof(Employee), "e");
Expression left = Expression.Property(pe, typeof(Employee).GetProperty("Country"));
Expression right = Expression.Constant("Sri Lanka");
Expression expression = Expression.Equal(left, right);
var lambda = Expression.Lambda<Func<Employee, bool>>(expression, pe).Compile();
var filteredEmployees = employees.Where(lambda);

And this is the output when I foreach on “filteredEmployees”.
image
Output

I am uploading the full sample to my OneDrive. Enjoy!.


Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment