C#中的IQueryable vs IEnumerable
概要
我们在应用开发中经常用到IQueryable 和 IEnumerable两个接口。如果这两个接口搞混,往往会对程序性能造成很大的影响。
本文以一个实例来区分这两个接口,说明在实际开发过程中,这两个接口如何使用,尤其是IQueryable 和接口IEnumerable中的LINQ扩展方法的使用。
基本定义
IEnumerable
IEnumerable 是一个接口,客户代码通过实现该接口的GetEnumerator方法,来返回一个具体的IEnumerator.。
在实际应用中,IEnumerable 面向内存对象,它会将所有的数据载入到内存中,再进行各种操作。IEnumerable 包含一系列操作内存对象的扩展方法。
IQueryable
IQueryable 是一个接口,一般通过第三方的Data Provider来实现接口中的方法。例如EntityFramework。
在实际应用中,IQueryable 面向Data Provider,为其创建查询的SQL语句。
实例说明
本文通过一个使用EntityFramework来查询农业银行在天津的分行数据,来说明两个接口在实际使用中的差别。
IEnumerable获取数据
关键代码如下:
using (var context = new BranchContext(connectionString)){IEnumerable<Branch> branches = context.Branches.Where( b => b.Id > 1);branches = branches.Take(2);foreach(Branch branch in branches){System.Console.WriteLine(branch.Name);}}
运行结果如下:
结果分析:
- SQL语句中只有Id >1 一个过滤条件。
- 数据库查询后,所有的查询结果全部载入内存IEnumerable对象中。
- IEnumerable的Take方法在内存中过滤出前两个分行数据,并显示。
IQueryable 获取数据
关键代码如下:
using (var context = new BranchContext(connectionString)){IQueryable<Branch> branches = context.Branches.Where( b => b.Id > 1);branches = branches.Take(2);foreach(Branch branch in branches){System.Console.WriteLine(branch.Name);}
}
运行结果如下:
结果分析:
- SQL语句中既有Id >1 一个过滤条件,又有top关键字过滤前两个查询结果。
- 第一条语句执行后,IQueryable只是为EntityFramework生成了查询语句,过滤条件是Id>1,并没有真正进行数据库查询。
- 第二条Take语句执行后, IQueryable为EntityFramework重新生成了查询语句,包括了top部分。
- Foreach语句触发了数据库查询,所以我们看到的SQL即包含Id > 1的过滤条件,又包含了top语句。
结论
IEnumerable中的Linq查询方法,只是针对内存对象。IQueryable中的Linq查询方法,是帮助第三放Data Provider生成查询的SQL语句。
所以我们在做大数据表服务器端分页操作时候,一定要小心。我们必须确保所有的查询方法都是基于IQueryable的,最后都能反应到SQL语句上。避免由于不慎使用 IEnumerable,将大数据表全部载入内存,再进行各种过滤操作的情况。那样做,会使服务器压力激增。
附录
完整C#代码
Branch.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace IQueryableIEnumerable
{[Table("t_branch")]public class Branch{[Required]public int Id { get; set; }[Required]public string Name { get; set; }[Required, Column("Addr")]public string Address { get; set; } [Timestamp]public byte[] RowVersion { get; set; }}
}
BranchContext.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IQueryableIEnumerable
{public class BranchContext : DbContext {private readonly ILoggerFactory loggerFactory = LoggerFactory.Create(ConventionForeignKeyExtensions => ConventionForeignKeyExtensions.AddConsole());private readonly string ConnectionString;public DbSet<Branch> Branches {get;set;}public BranchContext(string connectionString){ConnectionString = connectionString;}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseLoggerFactory(loggerFactory);optionsBuilder.UseSqlServer(ConnectionString);}}
}
Main 函数
using System;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Collections.Generic;
namespace IQueryableIEnumerable
{class Program{static void Main(string[] args){var connectionString = @"Server=PC-20210618NEZE\SQL2012EXPRESS;Database=BranchMngt;Trusted_Connection=True;MultipleActiveResultSets=true";using (var context = new BranchContext(connectionString)){IQueryable<Branch> branches = context.Branches.Where( b => b.Id > 1);branches = branches.Take(2);foreach(Branch branch in branches){System.Console.WriteLine(branch.Name);}} /* using (var context = new BranchContext(connectionString)){IEnumerable<Branch> branches = context.Branches.Where( b => b.Id > 1);branches = branches.Take(2);foreach(Branch branch in branches){System.Console.WriteLine(branch.Name);}} */}}
}
SQL建表语句和数据初始化
if object_id(N't_branch',N'U') is not null drop table t_branchcreate table t_branch (Id int primary key identity(1,1),Name nvarchar(50) not null,Addr nvarchar(200) not null,[RowVersion] [timestamp] NULL)insert into t_branch (Name,Addr) values(N'天津丽江道支行',N'天津市西青区李七庄街凌口村悦雅花园9号楼底商一层'),(N'中国农业银行',N'天津市南开区凌宾路'),(N'天津宾水西道支行',N'天津市南开区宾水西道阳光公寓A座首层、二层'),(N'天津李七庄支行',N'天津市河西区纪庄子道4号'),(N'天津阳光支行',N'天津市南开区港宁西路27号'),(N'环湖中路支行',N'天津市河西区环湖中路10号(13路终点站)')
C#中的IQueryable vs IEnumerable相关推荐
- IQueryable 和 IEnumerable
IQueryable 和 IEnumerable 其实,对于上面的即有过虑又有排序的条件查询Linq语句,EF是读取数据库中整个Books表中的数据到内存,还是根据Linq查询语句智能的生成SQL再执 ...
- IQueryable和IEnumerable区别
IQueryable 和IEnumerable总结 1,IEnumerable<T> result = (from t in context.Table order by t.Id se ...
- IQueryable和IEnumerable,IList的区别
IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution) IQueryable和IEnumerabl ...
- IQueryable和IEnumerable学习
IQueryable和IEnumerable区别 开始了解IQueryable和IEnumerable前,我们先看一下源码 由上面的图片可以得知IQueryable接口继承自IEnumerable接口 ...
- 对IQueryable和IEnumerable的认识
** IQueryable和IEnumerable的区别 public static IQueryable<TSource> Where<TSource>(this IQuer ...
- C# IQueryable 和 IEnumerable 的区别
这是 EF Core 系列的最后一篇文章,按照上一篇的计划,我们最后就讲一讲 IQueryable 和 IEnumerable 的区别. 点击上方或后方蓝字,阅读 EF Core 系列合集. 在前面的 ...
- 【C#】IQueryable和IEnumerable的区别
IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...
- IQueryable 和 IEnumerable 的区别
在C#中使用 Linq to sql 时,经常搞混 IQueryable 和 IEnumerable 这两种类型,本文简单分析下它们之间的区别和使用场景. 前言 不管是Linq to object,还 ...
- EFCore——IQueryable与IEnumerable的区别(13)
IQueryable与IEnumerable的区别 一.IQueryable与IEnumerable的简单实例 二.IQueryable与IEnumerable的区别 一.IQueryable与IEn ...
最新文章
- 投影串口测试程序_【原创】串口通信测试程序
- 超酷图片压缩工具,就是不支持批量
- VS与Win7 共舞:用户界面特权隔离
- h5手机端浏览器机制_H5测试介绍
- Executor 执行器接口笔记
- 【深度学习】解决物体检测中的小目标问题
- The TensorFlow library wasn‘t compiled to use SSE instructions, but these are available on your mach
- MySQL Performance-Schema(二) 理论篇
- synchronized锁的升级
- js高级编程_这位设计师用Processing把创意编程玩到了极致!
- 信息加密之信息摘要加密MD2、MD4、MD5
- python中scrapy是什么_python爬虫中scrapy组件有哪些?作用是什么?
- 蓝桥杯 ADV-158 算法提高 新建Microsoft Word文档
- Learning to Ranking
- 小米/VIVO/OPPO全系列救砖+解锁+工具+教程+激活账户技术
- c语言程序设计操作,c语言编程入门相关详细操作
- MMDetection学习教程(一)
- Docker-禁用userland代理
- LINUX中DNS服务器反向解析
- 有符号数和无符号数在计算机中怎么区分?