Build IQueryable.Any with expression trees for LINQ queries

I am building the SQL WHERE clause dynamically using the System.Linq.Expressions.Expression class. It works well for simple articles, for example. to add a PhaseCode = X clause, I do the following:

var equalTarget = Expression.Constant(phaseCode, typeof(int?)); var phaseEquals = Expression.Equal(Expression.PropertyOrField(projParam, "PhaseCode"), equalTarget); 

However, now I am trying to create an expression that will return a record if the project has been assigned to a specific group. The project and the group have many-to-many relationships. Without expression trees, I would do it like this:

 db.Projects.Where(p => .... && p.GroupsAssigned.Any(g => g.ID == groupId)) 

However, I cannot find a way to express this with the Expression class. There are actually two things that I cannot understand:

  • How to navigate between tables
  • How to make x.Any ()

Any help is greatly appreciated.

+7
source share
1 answer

Calling an extension method, such as Enumerable.Any or Queryable.Any , is just a static method, call the sequence and lambda expression that you created for the WHERE . You can use Expression.Call to do this:

 // for Enumerable.Any<T>(IEnumerable<T>,Predicate<T>) var overload = typeof(Enumerable).GetMethods("Any") .Single(mi => mi.GetParameters().Count() == 2); var call = Expression.Call( overload, Expression.PropertyOrField(projParam, "GroupsAssigned"), anyLambda); 

For Queryable.Any<T> you need to flip this into a method:

 static Expression BuildAny<TSource>(Expression<Func<TSource, bool>> predicate) { var overload = typeof(Queryable).GetMethods("Any") .Single(mi => mi.GetParameters().Count() == 2); var call = Expression.Call( overload, Expression.PropertyOrField(projParam, "GroupsAssigned"), predicate); return call; } 

Although it seems strange that you cannot do this with a regular request.

+10
source

All Articles