Using Linq, it is easy to execute a function to project an IEnumerable.
var orders = new List<Order>();
orders.Where(x => x.Id > 50).Select(x => new SomethingElse(x.Name));
Using EntityFramework and IQueryable, this is not possible. You instead get an unsupported exception at runtime because you cannot have a function inside the Select.
Does not work:
var db = new Order(); db.MyEntities.Where(x => x.Id > 50).Select(x => new SomethingElse(x.Name)).Take(10);
Does there exist, or is it possible to create a way for the above to work?
I understand it doesn't work because it cannot convert the function into something SQL can understand, however, if there was an extension method called 'Execute' that could execute in memory after executing all the linq before and after it, would that work?
The database would pull only > 50 AND only TOP 10, only after would it be
var db = new Order(); db.MyEntities.Where(x => x.Id > 50).Execute(x => new SomethingElse(x.Name)).Take(10);
To clarify: The requirement is to keep it as IQueryable even after the Sleect()
No, because you'd need to ship all the data back to the database to do the final part.
Typically you have an extra Select
to get just the information you need within the query (using an anonymous type if there are multiple properties you need), then do all the rest locally:
var query = db.MyEntities
.Where(x => x.Id > 50)
.Select(x => x.Name) // All we need - keep the query cheap
.Take(10)
.AsEnumerable()
.Select(x => new SomethingElse(x));
Note that you may run into Queryable.AsQueryable
, which does produce an IQueryable<T>
from an IEnumerable<T>
- but it doesn't do what you want. If the source isn't really a queryable, it will "fake" it but not connect it back to the database, which is what you're after.
See more on this question at Stackoverflow