I have a Linq provider that sucessfully goes and gets data from my chosen datasource, but what I would like to do now that I have my filtered resultset, is allow Linq to Objects to process the rest of the Expression tree (for things like Joins, projection etc)
My thought was that I could just replace the expression constant that contains my IQueryProvider with the result-sets IEnumerable via an ExpressionVisitor and then return that new expression. Also return the IEnumerable's provider from my IQueryable...but this does not seem to work :-(
Any idea's?
Edit: Some good answers here, but given the form...
var qry = from c in MyProv.Table<Customer>()
Join o in MyProv.Table<Order>() on c.OrderID equals o.ID
select new
{
CustID = c.ID,
OrderID = o.ID
}
In my provider I can easily get back the 2 resultsets from Customers and Orders, if the data was from a SQL source I would just construct and pass on the SQL Join syntax, but it this case the data is not from a SQL source so I need to do the join in code...but as I said I have the 2 result sets, and Linq to Objects can do a join...(and later the projection) it would be real nice to just substitute the Expression constants MyProv.Table<Customer>
and MyProv.Table<Order>
with List<Customer>
and List<Order>
and let a List<>
provider process the expression...is that possible? how?
The kind of thing that I was after was replacing the Queryable<> constant in the expression tree with a concrete IEnumerable (or IQueryable via .AsQueryable()) result set...this is a complex topic that probably only makes any sense to Linq Provider writers who are knee deep in expression tree visitors etc.
I found a snippet on the msdn walkthrough that does something like what I am after, this gives me a way forward...
using System;
using System.Linq;
using System.Linq.Expressions;
namespace LinqToTerraServerProvider
{
internal class ExpressionTreeModifier : ExpressionVisitor
{
private IQueryable<Place> queryablePlaces;
internal ExpressionTreeModifier(IQueryable<Place> places)
{
this.queryablePlaces = places;
}
internal Expression CopyAndModify(Expression expression)
{
return this.Visit(expression);
}
protected override Expression VisitConstant(ConstantExpression c)
{
// Replace the constant QueryableTerraServerData arg with the queryable Place collection.
if (c.Type == typeof(QueryableTerraServerData<Place>))
return Expression.Constant(this.queryablePlaces);
else
return c;
}
}
}