Ant
Ant

Reputation: 869

Combine OrderBy Expression with Where Expression

I found the following question that can combine multiple Expression<Func<T,bool>> expressions:

How to merge two C# Lambda Expressions without an invoke?

I'm wondering whether, using a similar technique, how you go about merging a .OrderBy Expression<Func<Entity, Key>> with a .Where Expression<Func<Entity, bool>> into one Expression of type, or inheriting from type, System.Linq.Expressions.Expression.

I'm making a really cut down QueryProvider-style class for taking T => T == ... Func's via public methods .Where and .OrderBy. This is with the intention that the expression this class builds gets passed to a QueryTranslator to create suitable SQL.

A QueryTranslator of this style, when called from a QueryProvider, typically takes one System.Linq.Expressions.Expression as an argument which it then translates to SQL.

I can follow through and understand the question above for merging two .Where Funcs. The following blog post was particularly useful for this, and I traced through each of the examples:

http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx

This CodeProject article was also useful:

http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C

When combining a .OrderBy Func with a .Where Func however the two have different generic arguments. In the case of the .Where it's a Func<Entity, bool>, and in the case of the .OrderBy it's a Func<Entity, Key>.

Merging these two Expressions, on the surface, isn't as straight forward as merging two with the same generic arguments.

The in-built Func-Expression-producing-engine (unsure of exact term) is able to combine a .Where Func with a .OrderBy Func. I'm curious about what goes on under the hood when these two expressions are merged to become one System.Linq.Expressions.Expression. Is it possible, and if so how would you go about combining an Expression<Func<Entity, bool>> with an Expression<Func<Entity,Key>> assuming the Entity is of the same type in each Expression?

Upvotes: 5

Views: 2156

Answers (2)

Ant
Ant

Reputation: 869

I think where this question got ambiguous is because it's kind of unanswerable.

I was trying to build one super-expression, like how the IQueryable<> expression builder works with .Where and .OrderBy expressions all in one expression.

Without a subject, however, my limited understanding of Expressions and Expression Trees seems to suggest it's not possible.

To combine a .Where expression with a .OrderBy expression into one Expression you need MethodCallExpression's to separate the two LambdaExpressions.

The MethodCallExpression needs a subject to call the Method on. This is where the IQueryable<> gets used.

I've altered my Query class to keep all the LambdaExpression's separate, and these then get passed to the QueryTranslator separately. The QT merges the output SQL into the right places.

This is as opposed to an IQueryable<> QueryProvider that analyses one super-Expression and outputs SQL into the right places based on MethodCallExpression's in the Expression.

Upvotes: 0

Amy B
Amy B

Reputation: 110221

public IQueryable<T> ApplyExpressions<T, TKey>(
  Expression<Func<T, TKey>> sortBy,
  Expression<Func<T, bool>> filterBy,
  IQueryable<T> source)
{
  return source.Where(filterBy).OrderBy(sortBy);
}


IQueryable<Customer> query = ApplyExpressions<Customer, int>(
  c => c.Age,
  c => c.Name.StartsWith("B"),
  myDC.Customers)

Expression queryExpression = query.Expression;  //tada

Upvotes: 3

Related Questions