IQueryable OrderBy with Func <TModel,TValue>:发生了什么

Rap*_*aus 7 c# linq-to-entities

使用此问题给出的代码, 在传递选择器函数时,OrderBy不会转换为SQL

Func<Table1, string> f = x => x.Name;
var t = db.Table1.OrderBy(f).ToList();
Run Code Online (Sandbox Code Playgroud)

翻译的SQL是:

SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Name] AS [Name]
FROM [dbo].[Table1] AS [Extent1]
Run Code Online (Sandbox Code Playgroud)

好.

我可以理解代码编译:IQueryable继承自IEnumerable,有一个带有Func<TModel, TValue>as参数的OrderBy方法.

我可以理解,ORDER BY子句不是在SQL中生成的,因为我们没有传递一个Expression<Func<TModel, TValue>>OrderBy参数(IQueryable的参数)

但是现场背后会发生什么?"错误的"OrderBy方法会发生什么?没有 ?我无法看到如何以及为什么......我夜晚的任何光明?

And*_*tan 5

因为f是委托而不是表达式,所以编译器选择IEnumerable OrderBy扩展方法而不是表达方法IQueryable.

这意味着所有结果都是从数据库中获取的,因为然后在内存中完成排序,就像它是Linq to Objects一样.也就是说,在内存中,只能通过获取所有记录来完成排序.

当然,实际上在你开始枚举结果之前,这种情况实际上并没有发生 - 在你的情况下,你直接做了因为你急切地加载你的调用结果ToList().

更新以回应您的评论

从引入歧义的角度来看,你的问题似乎与IQueryable/ IEnumerable二元性是"危险的"有关.它真的不是:

t.OrderBy(r => r.Field)
Run Code Online (Sandbox Code Playgroud)

C#首先将lambda视为Expression<>首先,因此如果t是,IQueryableIQueryable选择扩展方法.它与string传递给带有stringobject重载的重载方法的变量相同- string将使用该版本,因为它是最佳表示.

正如Jeppe指出的那样,实际上是因为在继承接口之前使用了直接接口

t.AsEnumerable().OrderBy(r => r.Field)
Run Code Online (Sandbox Code Playgroud)

C#再也看不到了IQueryable,所以将lambda视为a Func<A, B>,因为这是它的下一个最佳表示.(相当于之前objectstring/ object类比中可用的方法.

最后你的例子:

Func<t, string> f = r => r.Field;
t.OrderBy(f);
Run Code Online (Sandbox Code Playgroud)

没有可能的方式,开发人员编写的代码可以预计这将被视为一个较低等级组件的表达式转换为SQL,除非开发商根本不理解的委托和表达之间的区别.如果是这种情况,那么一点点阅读就能解决问题.

我认为在开始使用新技术之前要求开发人员进行一些阅读是不合理的.尤其是在MSDN的辩护中,这个特定的主题得到了很好的报道.

我现在意识到通过添加这个编辑,我现在已经使@IanNewson的注释无效 - 但我希望它提供一个有意义的引人注目的论点:)