FirstOrDefaultAsync().ContinueWith()与Select().FirstOrDefaultAsync()有何差异?
两段EF Core代码的区别分析
你的理解不完全准确,两段代码的核心差异在于ToModel()的执行时机、执行环境,具体区别如下:
执行位置与逻辑差异
- 代码段1:
Select(x => x.ToModel())属于EF Core查询表达式的一部分,EF会优先尝试把ToModel()的逻辑转换为SQL语句在数据库端执行(前提是ToModel()是EF支持的可解析方法)。如果ToModel()包含无法被EF转换为SQL的逻辑,EF会先执行FirstOrDefaultAsync()对应的数据库查询(拉取实体全字段),再在内存中对结果执行转换。 - 代码段2:
FirstOrDefaultAsync()会先完成数据库查询,将单个实体对象完整拉取到本地内存,再通过ContinueWith在客户端内存中执行ToModel()转换,转换过程完全和数据库无关。
- 代码段1:
异步行为与异常处理
- 代码段1:使用
await直接等待异步操作完成,异常会直接抛出,符合常规异步代码的错误处理逻辑,写法更直观。 - 代码段2:
ContinueWith是Task的延续操作,若FirstOrDefaultAsync()抛出异常,需要在延续逻辑中通过x.IsFaulted判断异常情况;即便直接await整个Task,异常也会抛出,但整体写法不如代码段1简洁易读。
- 代码段1:使用
性能表现
- 代码段1:如果
ToModel()能被EF解析为SQL,只会从数据库拉取转换后需要的字段,大幅减少网络传输的数据量;若无法解析,才会拉取实体全字段。 - 代码段2:一定会拉取实体的全部字段到内存,当实体包含大量非必要字段时,会增加网络开销和内存占用。
- 代码段1:如果
对你理解的修正
你所说的「第二段在数据库请求完成后再执行转换」是完全正确的;但第一段并非总是让数据库完成转换——只有当ToModel()的逻辑能被EF转换为SQL时,才会在数据库端完成转换,否则也是在数据库请求完成后(内存中)执行转换。
内容的提问来源于stack exchange,提问作者hunB
相关产品推荐
相关产品推荐

