两段C# LINQ代码的差异疑问:为何生成的T-SQL查询不同?
为什么两段EF查询生成的SQL差异这么大?
这是个非常典型的EF查询翻译逻辑问题,我来给你掰扯清楚:
代码1的行为:精准查询需要的列
第一段代码里,你直接在Select里构造了RequestSellDto:
.Select(x => new RequestSellDto { ConsoleName = x.Name })
EF的查询翻译器(不管是EF Core还是传统EF)能完整解析这个lambda表达式的表达式树——它能明确看到你只用到了实体x的Name属性。所以它会直接把这个投影逻辑转换成对应的SQL,只查询Name这一列,类似这样:
SELECT [x].[Name] AS [ConsoleName] FROM [RequestSellctx] AS [x]
这种属于服务器端评估,所有投影逻辑都在数据库端完成,效率更高。
代码2的行为:被迫加载全表列
第二段代码里,你把映射逻辑抽到了自定义的Map方法里:
.Select(x => Map(x))
这里的关键问题是:EF根本看不懂你自定义的Map方法内部做了什么。EF的查询翻译器只能解析它内置支持的表达式(比如直接的属性访问、EF内置的函数等),对于你自己写的方法,它无法拆解里面的逻辑,不知道你只用到了Name属性。
为了让Map方法能正常执行,EF只能先把整个RequestSell实体的所有列都从数据库加载到内存里,然后再在客户端(你的应用程序内存)里调用Map方法来构造DTO。所以生成的SQL会查询表的所有列,类似:
SELECT [x].[name], [x].[region] FROM [RequestSellctx] AS [x]
这种属于客户端评估,会额外加载不需要的列,性能上不如第一种方式。
怎么让代码2也能生成精准SQL?
如果想保留Map这样的复用逻辑,同时让EF能生成只查需要列的SQL,可以把Map改成表达式树,比如:
private static Expression<Func<RequestSell, RequestSellDto>> Map() { return x => new RequestSellDto { ConsoleName = x.Name }; } // 调用的时候用: var model = context.RequestSellctx.Select(Map()).ToList();
这样EF就能解析这个表达式树,同样生成只查Name列的SQL了。
内容的提问来源于stack exchange,提问作者Milad Jafari
相关产品推荐
相关产品推荐

