IQueryable 和 IEnumerable

IQueryable 和 IEnumerable

其实,对于上面的即有过虑又有排序的条件查询Linq语句,EF是读取数据库中整个Books表中的数据到内存,还是根据Linq查询语句智能的生成SQL再执行查询,完全编码者来决定的。我们打开BookShop.Domain工程的BookRepository类文件,请注意该类中Books属性的返回类型:

...
public IQueryable<Book> Books {
get { return context.Books; }
}

上篇博文中,我们对使用IQueryable作为返回类型提了个疑问:为什么用IQueryable而不用IEnumerable作为返回类型?答案是:使用IQueryable,EF会根据调用者的Linq表达式先生成相应的SQL查询语句,然后到数据库中执行查询,查询出来的数据即是用户想要的数据;而使用IEnumerable,Linq表达式的过滤、排序等操作都是在内存中发生的,即EF会先从数据库中把整个表的数据查询出来放在内存中,然后由调用者使用Linq语句进行过滤、排序等操作。是不是这样呢?我们来监视一下两种情况EF生成的SQL语句就知道了。

我们先来看看使用IQueryable的情况。重新运行一下程序,然后使用SQL Server Management Studio的活动和监视器查看一下我们的BookShop应用程序所执行的SQL语句,结果如下:

IQueryable 和 IEnumerable

结果证明使用IQueryable,EF是先根据Linq表达式生成相应的SQL语句再执行查询的。

我们再稍稍修改一下代码来看看用IEnumerable的情况。把BookRepository类修改如下:

public class BookRepository : IBookRepository {
private EFDbContext context = new EFDbContext(); public IEnumerable<Book> Books {
get { return context.Books; }
}
}

当然BookRepository类所实现的IBookRepository接口(在BookShop.Domain工程的Abstract文件夹中)也要改一下:

public interface IBookRepository {
IEnumerable<Book> Books { get; }
}

再重新运行一下应用程序,用活动和监视器查看最后执行的SQL语句如下图:

IQueryable 和 IEnumerable

我们看到改用IEnumerable后,EF生成的SQL没有任何过滤、排序等的操作,它一次把表中的所有数据都Select出来,和上面写的Linq表达式一点都没关系。

IQueryable虽然可以很智能地根据Linq表达式生成相应的SQL语句,但毕竟有一个分析Linq表达式的过程,相对来说性能比IEnumerable要差。那么我们什么时候用IEnumerable,什么时候用IQueryable呢?我想,对于少量的数据(比如从数据库中读取应用程序相关的系统信息)和不需要对数据进行过滤操作的情况,用IEnumerable比较适合;对于数据量较大需要对数据进行过滤(比如分页查询)的情况,则用IQueryable比较合适。

上一篇:jdbc数据访问技术


下一篇:Spring 梳理-数据访问-DB