Entity FrameWork IEnumerable和IQueryable 导致全量查询问题
引言
以前用.net
写的东西,关于EF的坑因为不了解所以让我很难受,这算是把笔记搬过来了。
用EF的感觉我很喜欢,因为我确实更喜欢手写sql
语句,Linq
的语法更让我舒服,这就像是在用Java
开发时我喜欢用mybatis
而讨厌使用hibernate
。
IEnumerable和IQueryable
我在看一本老外写的c# .net mvc5的书的时候,当时关注的是项目整体的设计过程和模式,其余的重点在Razor
,Ninject
之类的东西,没有关注EF
这个玩意,因为我当时想的是ORM框架
都差不多,它的栗子是这么写的:
public class EFDbContext : DbContext
{
public DbSet<Entities.Config> Configs { get; set; }
public DbSet<Entities.Infomation> Infomations { get; set; }
}
public class EFConfigsRepository
{
public EFConfigsRepository() {
context = new EFDbContext();
}
private EFDbContext context;
public IEnumerable<Entities.Config> Configs
{
get {
return context.Configs;
}
}
}
然后我傻傻的就跟着做,然后发现数据量大的情况下,查询速度
开始变的非常慢
,我确信我的sql语句和索引没有任何问题
。
无奈打开sql的分析工具,跟踪每一条执行语句,因为我当时网上找的EF打印SQL语句的方法一个都没用,最后虽然用到了dbContext.Database.Log = s => System.Diagnostics.Trace.WriteLine(s.ToString());
原因分析
在EFConfigsRepository
写的时候,我直接按照它的例子写成了IEnumerable
,这导致了在Linq语法被分析成SQL语句之前
,这段查询
就已经被执行
了(select * from xxxx),这就导致实际上Linq的语句并没有被解释成SQL语句
,而是整表扫描取了整表的数据,之后的Linq语法
实际就是在内存中对c#原生的对象在操作
。
正确做法应该是IQueryable
,在Linq的最后
使用ToList
才去真正查询数据库。