Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Linq expression dynamically containing a subquery

I recently stumpled upon the problem to dynamically create Linq expressions during runtime. Most examples I found deal with the rather simple task of just comparing one property of a given database entity with a single parameter. Like so:

 Session.Query.Where(m => m.Name.Contains("test"))

Which could also be achieved with a far more generic approach like this:

var item = Expression.Parameter(typeof (MyClass), "item");
var property = Expression.Property(item, "Name");
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var searchExpression = Expression.Constant(searchString, typeof(string));
var containsMethodExpression = Expression.Call(property, containsMethod, searchExpression);
var lambda = Expression.Lambda<Func<MyClass, bool>>(containsMethodExpression, item);
query = query.Where(lambda);    

However, sometimes the task is somewhat more complex and one wants to attain something like the following:

Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")));

Where "SpecialProperty" is of the type List<> and the property "Name" is of the type string.

Is it possible to build a Linq expression like this dynamically and how could this be achieved? Are there any performance concerns regarding this approach?

like image 950
UnclePaul Avatar asked Mar 03 '12 10:03

UnclePaul


People also ask

Are there any examples of building a dynamic query using LINQ expressions?

The examples below are all related to this repository. SQL Server and .NET Core power the application and it contains three examples of building a dynamic query using LINQ expressions.

How do I create a dynamic lambda expression from a query?

The query will contain a Where clause and we will create a dynamic Lambda expression in the Where clause. If you open a class on any .NET project, and import the library "System.Linq.Expressions", you can call the class "Expression" and there are a large number of static methods within this class.

What are LINQ expressions?

LINQ expressions are a very powerful tool to filter and transform data. I hope this example helped demystify how expression trees are built. Of course, parsing the expression tree feels a little like magic.

How to convert LINQ to Lambda in Entity Framework?

There is a way around this and it comes in the form of LINQ expressions. You can keep on building up each part of the LINQ expression bit by bit. And when you are happy, you can convert it into a Lambda expression ready to be used in Entity Framework.


2 Answers

Found a solution that is working in my particular use case and does exactly what I was looking for.

/* 
building expression tree 
example: Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")))
*/ 

var innerItem = Expression.Parameter(typeof(MyInnerClass), "f");
var innerProperty = Expression.Property(innerItem, "Name");
var innerMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var innerSearchExpression = Expression.Constant(searchString, typeof(string));
var innerMethodExpression = Expression.Call(innerProperty, innerMethod, new[] { innerSearchExpression });
var innerLambda = Expression.Lambda<Func<MyInnerClass, bool>>(innerMethodExpression, innerItem);

var outerItem = Expression.Parameter(typeof(MyOuterClass), "m");
var outerProperty = Expression.Property(outerItem, info.Name);
/* calling a method extension defined in Enumerable */
var outerMethodExpression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(MyInnerClass) }, outerProperty, innerLambda);
var outerLambda = Expression.Lambda<Func<MyOuterClass, bool>>(outerMethodExpression, outerItem);
query = query.Where(outerLambda);

This rather dowdy approach is needed instead of the more elegant single line LINQ-Expression to allow for parametrization of types and method names. However, I of course wouldn't mind other suggestions and ideas on possible performance penalties.

It is very likely that this code snippet could also assist in solving How to produce a Subquery using non-generic Lambda.

like image 161
UnclePaul Avatar answered Sep 30 '22 11:09

UnclePaul


I recommend you look at these links:

Joseph and Ben Albahari's PredicateBuilder

The LINQ dynamic query library

I haven't used either for a while, but one or the other should help.

like image 31
Phil Avatar answered Sep 30 '22 12:09

Phil