With the code given from this question
OrderBy is not translated into SQL when passing a selector function
Func<Table1, string> f = x => x.Name;
var t = db.Table1.OrderBy(f).ToList();
The translated SQL is:
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name]
FROM [dbo].[Table1] AS [Extent1]
OK.
I can understand that the code compiles : IQueryable inherits from IEnumerable, which have an OrderBy method taking a Func<TModel, TValue> as parameter.
I can understand that the ORDER BY clause is not generated in SQL, as we didn’t pass an Expression<Func<TModel, TValue>> as the OrderBy parameter (the one for IQueryable)
But what happens behind the scene ? What happens to the “wrong” OrderBy method ? Nothing ? I can’t see how and why… Any light in my night ?
Because
fis a delegate rather than an expression, the compiler picks theIEnumerableOrderByextension method instead of theIQueryableone.This then means that all the results are fetched from the database, because the ordering is then done in memory as if it were Linq to Objects. That is, in-memory, the ordering can only be done by fetching all the records.
Of course, in reality this still doesn’t actually happen until you start enumerating the result – which in your case you do straight away because you eager-load the result with your call to
ToList().Update in response to your comment
It seems that your question is as much about the
IQueryable/IEnumerableduality being ‘dangerous’ from the point of view of introducing ambiguity. It really isn’t:C# sees the lambda as an
Expression<>first and foremost so iftis anIQueryablethen theIQueryableextension method is selected. It’s the same as a variable ofstringbeing passed to an overloaded method with astringandobjectoverload – thestringversion will be used because it’s the best representation.As Jeppe has pointed out, it’s actually because the immediate interface is used, before inherited interfaces
C# can’t see an
IQueryableany more, so treats the lambda as aFunc<A, B>, because that’s it’s next-best representation. (The equivalent of only anobjectmethod being available in mystring/objectanalogy before.And then finally your example:
There is no possible way that a developer writing this code can expect this to be treated as an expression for a lower-level component to translate to SQL, unless the developer fundamentally doesn’t understand the difference between a delegate and an expression. If that’s the case, then a little bit of reading up solves the problem.
I don’t think it’s unreasonable to require a developer to do a little bit of reading before they embark on using a new technology; especially when, in MSDN’s defence, this particular subject is covered so well.
I realise now that by adding this edit I’ve now nullified the comment by @IanNewson below – but I hope it provides a compelling argument that makes sense 🙂