Executing part of an IQueryable query and porting the rest to Linq for objects

I have a Linq provider that successfully sends and receives data from my selected data source, but now I would like to do what I have a filtered result set, allows Linq to Objects to process the rest of the expression tree (for things like Joins, projection, etc.)

My thought was that I can simply replace the expression constant containing my IQueryProvider with the IEnumerable result sets via ExpressionVisitor and then return this new expression. Also return an IEnumerable provider from my IQueryable ... but this does not seem to work: - (

Any idea?

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 return 2 result sets from clients and orders, if the data was from an SQL source, I would just build and pass the SQL Join syntax, but in this case the data is not from an SQL source, so I need to make a connection in the code. .. but, as I said, I have 2 sets of results, and Linq to Objects can make a connection ... (and later projection) it would be very nice to just replace the expression Constants MyProv.Table<Customer> and MyProv.Table<Order> with List<Customer> and List<Order> , and let the List<> provider handle the expression ... is this possible? as?

+7
c # linq expression-trees iqueryable
Mar 30 '09 at 0:15
source share
5 answers

What I did after replaced the Queryable <> constant in the expression tree with a specific IEnumerable result set (or IQueryable via .AsQueryable ()), this is a complex topic that probably only makes sense to Linq Provider authors who are deeply buried in visitors expression tree etc.

I found a snippet in passing msdn that does something like what I need, it 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; } } } 
+3
Apr 28 '09 at 22:53
source share

Both of the previous answers work, but they are better read if you use AsEnumerable () to pass IQueryable to IEnumerable:

 // Using Bob code... var result = datacontext.Table .Where(x => x.Prop == val) .OrderBy(x => x.Prop2) .AsEnumerable() // <---- anything after this is done by LINQ to Objects .Select(x => new { CoolProperty = x.Prop, OtherProperty = x.Prop2 }); 

EDIT:

 // ... or MichaelGG's var res = dc.Foos .Where(x => x.Bla > 0) // uses IQueryable provider .AsEnumerable() .Where(y => y.Snag > 0); // IEnumerable, uses LINQ to Objects 
+5
Mar 30 '09 at 4:40
source share

If I do not understand, I just add .ToArray () to the linq method chain at the point where I want the linq provider to execute.

For example (think of Linq for SQL)

 var result = datacontext.Table .Where(x => x.Prop == val) .OrderBy(x => x.Prop2) .ToArray() .Select(x => new {CoolProperty = x.Prop, OtherProperty = x.Prop2}); 

Thus, through OrderBy () it translates to SQL, but Select () is LINQ to Objects.

+1
Mar 30 '09 at 1:15
source share

If you implemented a repository template, you could get away by simply providing back an IQueryable and an abstract table.

Example:

 var qry = from c in MyProv.Repository<Customer>() Join o in MyProv.Repository<Order>() on c.OrderID equals o.ID select new { CustID = c.ID, OrderID = o.ID } 

and then just create your provider to simulate the IQueryable template in the repository method, as shown in the figure in this article .

Thus, you can write all kinds of providers to use everything you need. You may have a SQL LINQ 2 provider or an entry in a memory statement to test the device.

The repository method for the SQL LINQ 2 provider looks something like this:

 public IQueryable<T> Repository<T>() where T : class { ITable table = _context.GetTable(typeof(T)); return table.Cast<T>(); } 
+1
Jul 01 2018-10-10T00:
source share

Rob's answer is good, but makes a full listing. You can use to save extension method syntax and lazy evaluation:

 var res = ((IEnumerable<Foo>)dc.Foos .Where(x => x.Bla > 0)) // IQueryable .Where(y => y.Snag > 0) // IEnumerable 
0
Mar 30 '09 at 3:06
source share



All Articles