score:2
When you break down the expression tree that gets passed into the IQueryProvider
, you will see the call chain of LINQ methods. Remember that generally LINQ works by chaining extension methods, where the return value of the previous method is passed into the next method as the first argument.
If we follow that logically, that means the very first LINQ method in the chain must have a source argument, and it's plain from the code that its source is, in fact, the very same IQueryable
that kicked the whole thing off in the first place (your ConcatenatingQueryable
).
You pretty much got the idea right when you built this - you just need to go one small step further. What we need to do is re-point that first LINQ method to use the actual source, then allow the execution to follow its natural path.
Here is some example code that does this:
public object Execute(Expression expression)
{
var query1 = ChangeQuerySource(expression, Expression.Constant(source1));
var query2 = ChangeQuerySource(expression, Expression.Constant(source2));
dynamic results1 = source1.Provider.Execute(query1);
dynamic results2 = source2.Provider.Execute(query2);
return Enumerable.Concat(results1, results2);
}
private static Expression ChangeQuerySource(Expression query, Expression newSource)
{
// step 1: cast the Expression as a MethodCallExpression.
// This will usually work, since a chain of LINQ statements
// is generally a chain of method calls, but I would not
// make such a blind assumption in production code.
var methodCallExpression = (MethodCallExpression)query;
// step 2: Create a new MethodCallExpression, passing in
// the existing one's MethodInfo so we're calling the same
// method, but just changing the parameters. Remember LINQ
// methods are extension methods, so the first argument is
// always the source. We carry over any additional arguments.
query = Expression.Call(
methodCallExpression.Method,
new Expression[] { newSource }.Concat(methodCallExpression.Arguments.Skip(1)));
// step 3: We call .AsEnumerable() at the end, to get an
// ultimate return type of IEnumerable<T> instead of
// IQueryable<T>, so we can safely use this new expression
// tree in any IEnumerable statement.
query = Expression.Call(
typeof(Enumerable).GetMethod("AsEnumerable", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(
TypeSystem.GetElementType(methodCallExpression.Arguments[0].Type)
),
query);
return query;
}
Source: stackoverflow.com
Related Articles
- Concatenating an IQueryable with an IEnumerable into an IQueryable
- Concatenating three lists into one with LINQ throws an exception
- Dynamically cast IEnumerable to IQueryable or dynamically call AsQueryable with LINQ Expressions
- Can't add a new record with an integer value into database by using linq from code C#
- Turning IEnumerable of struct with inner IEnumerable into single dictionary
- Cannot implicitly convert type IEnumerable to IQueryable with Entities
- How to Insert into Identity column with c# code
- Converting SQL code with Row_Number() into LINQ C# code
- concatenating IQueryable data sets with MVC and Entity Framework
- Split List into Sublists with LINQ
- Using IQueryable with Linq
- What's the difference between IQueryable and IEnumerable
- Split a collection into `n` parts with LINQ?
- Can I split an IEnumerable into two by a boolean criteria without two queries?
- Instantiate empty IQueryable for use with Linq to sql
- IEnumerable to string delimited with commas?
- What does this C# code with an "arrow" mean and how is it called?
- Is it possible to turn an IEnumerable into an IOrderedEnumerable without using OrderBy?
- Ambiguous Invocation IQueryable or IEnumerable
- IEnumerable cannot be used with type arguments
- Is there an IEnumerable implementation that only iterates over it's source (e.g. LINQ) once?
- Flatten List<string[]> into single string with one line for each element
- Converting iQueryable to IEnumerable
- Merge multiple Lists into one List with LINQ
- Returning a Distinct IQueryable with LINQ?
- Iterating through IQueryable with foreach results in an out of memory exception
- does converting IQueryable to IEnumerable execute the query again?
- List vs IEnumerable vs IQueryable when defining Navigation property
- If I cast an IQueryable as an IEnumerable then call a Linq extension method, which implementation gets called?
- Splitting an IEnumerable into two
- Newly created item field values
- IQueryable/Linq Orderby Fail: Sorts only a limited number of records
- Is there a workaround when using linq to create a searchPredicate that exceeds 2100 parameters?
- Convert a string in a List<int> using LINQ (cleaner way)
- Multiple outer Linq join
- SQL to LINQ Statement including Group By and Order By
- LINQ-2-SQL expansion of relationships on ToList()
- Automapper projection and union
- sql to linq query convert
- yield return empty character literal
- Return List with Maximum Count using Linq
- I'm having an issue reusing includes for EF 5. What am I doing wrong?
- Prevent adding duplicate items on ListView
- Selecting a XElement from a XDocument
- linq query one to one
- C# Insert missing records, from a list with linq?
- I cant get the values from xml document
- Create an ObservableCollection by filtering two ObservableCollections of the same type using LINQ and MVVM
- Move First 10 List Items to Another Item List
- Unable to cast object of type 'System.DBNull' to type 'System.String' On getting all Products