Building dynamic LINQ queries using Expression Trees and Func

Filtering an item from a list of items is easy but if the item to filter is not known at compile time then filtering a list will be little complicated.

Instead of writing dynamic filtering in C#, one might go for a Stored Procedure and write a dynamic query based on the input column name and execute the dynamic SQL statement.

In this post, we will see how to build the dynamic LINQ queries. Building dynamic LINQ expressions is easy but you need to have an idea on Func<T, TResult> and Expression Trees before we begin.

Querying on Seed data

For the purpose of the article, we will have the following list of user data.

What is a Func delegate?

Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter. - from MSDN

Func is a delegate type for a method that returns the value of the type T. You can use Func to reference a method.

For example, if we want to multiply two numbers, then with Func delegate we can write the following code

Back to our original dynamic LINQ, we’ll use Func delegate to have dynamic LINQ queries.

Dynamic Querying with Func

If we want to get the specific ID of the user in a list of users then we will write the following LINQ on the list of users for different properties on the User model.

For filtering the ID property:

For FirstName?

Last name?

From our console app, we will supply a property name to filter on. So, can we have a switch statement to do this? (I know some of you don’t like the switch-case statement).

In the above code snippet, we declared a Func delegate (exp) at the top and based on the property name we will assign the necessary lambda expression to the func delegate and return the delegate back to the caller.

Once we get the Func delegate from the method, we will apply that delegate on a list of user data.

I don’t like the above solution, although it solves the problem. Because, the code violates Open-Closed principle and the code use switch-case statement.

Let’s do the real dynamic LINQ querying with Expression trees.

What is an Expression Tree?

An expression tree is a binary tree that will represent expressions. So, we have to build the expressions for the tree.

In C#, the expression trees concept is used to translate code into data.

With expression trees, we produce a data structure that represents your code.

Why do we need the expression trees now? We’ll use the expression trees to build our code as a data structure and we compile the expression tree to get a func delegate which can be used to filter the items.

Building dynamically with Expression trees

To represent x => x.LastName == "Curry" in expression trees, we have to write the following code.

In the above code we have the following line

This makes the constant expression of type string but what if we give ID as the input to the program and run it. Well, it breaks with the following exception.

System.InvalidOperationException: ‘The binary operator Equal is not defined for the types ‘System.Int32’ and ‘System.String’.’

To fix this we have to get rid of that line and we will use the TypeDescriptor to convert our value to the appropriate type.

As said, the following code will convert from a string to its own type of data.

You can also use int.TryParse to test if the string is an integer. If we chose this approach then we have to use if/else or switch-case statements to make that constant expression and also have to handle the value expression.

With the TypeDescriptor now in place let’s see the entire code.

The above code blocks is a tabbed content check the second tab for the dynamic LINQ generation using Expression Trees.

Let’s try the code in dotnet fiddle and see it in action.

In the output window of the dotnet fiddle, try with ID property with the value within 1, 2, 3 or FirstName/LastName with the names “Kevin”/“Curry”.

Cases not handled in the code

Note that the following cases were not handled in the above code.

• Giving property names with spaces will cause the program to throw an exception as the property with names(ex: First name) is not in the User model.
• Providing a value that is not in the user seed data will cause the program to end without providing any result.

Source Code on GitLab

The source code of the above example snippets and demo in the dotnetfiddle is available on GitLab.

Conclusion

The old way of doing things dynamic is to write a stored procedure with a ton of IF statements and build a raw SQL query and then execute it at the end.

Instead of writing the dynamic SQL queries it is better to build the Expression Trees or Func and then use it against the data to filter the result so that we can test the code.

One might argue that we can filter a list of item dynamically with reflection, but reflection will be slow if the model class (in our case the User class) has too many properties.