.NET IEnumerable本质是什么?为何转接口后EF查询逻辑改变?
为什么将DbSet转为IEnumerable后调用First()会全表加载?
首先明确两个核心接口的本质差异:
- IEnumerable
:仅定义了获取枚举器( GetEnumerator())的能力,它的扩展方法(比如First())都在System.Linq.Enumerable类中,这些方法的逻辑是在内存中遍历枚举序列——也就是说,需要先把所有数据加载到内存,才能逐个枚举并找到第一个元素。 - IQueryable
:继承自 IEnumerable<T>,但额外提供了表达式树(Expression)和查询提供者(IQueryProvider)的支持。它的扩展方法(比如First())在System.Linq.Queryable类中,这些方法会把查询逻辑打包成表达式树,交给EF的查询提供者翻译成对应的SQL(比如SELECT TOP 1 ...),在数据库端执行后再返回结果。
回到你的代码:
IEnumerable<EntityObject> m = DbContext.GetDbSet<EntityObject>(); var x = m.First();
DbSet<T>本身实现了IQueryable<T>接口,但当你把它赋值给IEnumerable<T>类型的变量时,后续调用First()时,编译器会绑定到Enumerable.First()而不是Queryable.First()。
Enumerable.First()的逻辑是:调用m.GetEnumerator()获取枚举器,然后逐个枚举元素直到找到第一个——而EF的DbSet枚举器在被遍历的时候,会触发全表数据的加载(因为要提供枚举所需的所有元素),这就是为什么会先把整张表加载到内存再取第一个元素。
针对你最后一个问题:将对象视为IEnumerable
内容的提问来源于stack exchange,提问作者F Dev
相关产品推荐
相关产品推荐

