IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树
关于IEnumerable和IQueryable的区别,这事还要从泛型委托Func<T>说起。来看一个简单的泛型委托例子:
class Program
{
static void Main(string[] args)
{
Func<int, bool> f = i => i > 5;
Console.WriteLine(f(3));
Console.WriteLine(f(10));
Console.ReadKey();
}
}
Func<T>是"语法糖",实际上,编译器在内部会生成一个临时方法,再执行该方法。等同于如下:
class Program
{
static void Main(string[] args)
{
Func<int, bool> f = DoSth;
Console.WriteLine(f(3));
Console.ReadKey();
}
static bool DoSth(int i)
{
return i > 5;
}
}
以上,.NET内部运作的路径是:编写C#代码→编译器编译成中间语言IL→运行时JIT编译成本地语言执行
■ 使用表达式树 Expression Tree
可是,有时候我们希望在运行时执行代码,该怎么办呢?
.NET为我们提供了Expression Tree,允许我们在运行时执行代码。
比如以上Func<int, bool> f = i => i > 5;这个表达式,Expression Tree这样理解这个表达式:
○ f是Expression<Func<int, bool>>类型,级Expression<TDelegate>类型
○ =>被理解成BinaryExpression类型
○ =>左右两边的i被理解成ParameterExpression
○ =>右边的5被理解成ConstantExpression
于是,如果我们用Expression Tree,在运行时执行代码,可以按如下写:
class Program
{
static void Main(string[] args)
{
//Func<int, bool> f = i => i > 5;
ParameterExpression iParam = Expression.Parameter(typeof (int), "i");
ConstantExpression constExp = Expression.Constant(5, typeof (int));
BinaryExpression greaterThan = Expression.GreaterThan(iParam, constExp);
Expression<Func<int, bool>> f = Expression.Lambda<Func<int, bool>>(greaterThan, iParam);
Func<int, bool> myDele = f.Compile();
Console.WriteLine(myDele(3));
Console.WriteLine(myDele(10));
Console.ReadKey();
}
}
■ IQueryable和IEnumerable的区别
现在,可以看一个IEnumerable的例子了:
class Program
{
static void Main(string[] args)
{
int[] intArr = new[] {1, 2, 3, 6, 8};
IEnumerable<int> result = Enumerable.Where(intArr, i => i > 5);
foreach (var item in result)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
来看一下Enumerable,实现了IEnumerable接口,它的定义:
再来看Queryable,实现了IQueryable接口,它的定义:
发现,Enumerable和Queryable很多方法同名,但参数接收的参数类型是不一样的,Enumerable接收的参数类型是委托Func<TDelegate>,Querable接收的参数类型是Expression<Func<TDelegate>>,其类型是Expression Tree,是表达式树。
所以,有关IEnumerable<T>的表达式是在编译期确定的,有关IQueryable<T>的表达式是在运行时确定的。
■ 在Entity Framework应用实例中体会IQueryable<T>
首先在控制台应用程序中应用Entity Framework组件。
创建有关Entity Framework的上下文类,类,初始数据:
public class Person
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class MyContext : DbContext
{
public MyContext() : base("myConn")
{
Database.SetInitializer(new DbInirializer());
}
public DbSet<Person> People { get; set; }
}
public class DbInirializer : CreateDatabaseIfNotExists<MyContext>
{
protected override void Seed(MyContext context)
{
IList<Person> people = new List<Person>();
people.Add(new Person(){Name = "张三",Age = 21});
people.Add(new Person() { Name = "李四", Age = 22 });
people.Add(new Person() { Name = "赵五", Age = 23 });
foreach (var item in people)
{
context.People.Add(item);
}
base.Seed(context);
}
}
以上,如果转到DbSet的定义,我们可以看到DbSet实现了IQueryable接口。
配置连接字符串。
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="myConn"
connectionString="Data Source=.;User=yourusename;Password=yourpassword;Initial Catalog=MyTest;Integrated Security=True"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
在主程序中:
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext())
{
foreach (var item in context.People)
{
Console.WriteLine(item.Name);
}
}
Console.ReadKey();
}
}
现在来体会IQueryable<T>的一些特性。
我们知道,DbSet实现了IQuerayble接口,于是上下文的的People属性类型是IQueryable<Person>。
通过,
IQueryable<Person> people = context.People;
得到的people是表达式,是sql语句,现在尝试打印不同情况下的people表达式。
class Program
{
static void Main(string[] args)
{
using (var context = new MyContext())
{
IQueryable<Person> people = context.People;
var r = new Random();
Func<bool> rBool = () => r.Next()%2 == 0;
Console.WriteLine(people);
if (rBool())
{
people = people.Where(p => p.Age > 21);
Console.WriteLine(people);
}
else
{
people = people.OrderBy(p => p.Age);
Console.WriteLine(people);
}
}
Console.ReadKey();
}
}
由此可以看出:IQueryable呈现给我们的是表达式而不是集合,通过这个表达式可以按需加载满足条件的数据。
IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树相关推荐
- IEnumerable和IQueryable的区别
IEnumerable<T>在.Net2.0中我们已经很熟悉了.你想要利用Foreach迭代吗?实现 IEnumerable<T>吧!你想直接做为数据源绑定到控件吗?使用IEn ...
- 浅谈 IEnumerable 与 IQueryable 的区别
原文地址:https://www.jeremyjone.com/856/,转载请注明. 开始之前 在写数据操作时,经常会与这两个接口打交道,它们有着几乎相同的方法,使用起来基本无二,甚至通过 As 方 ...
- IEnumerable和IQueryable在使用时的区别
最近在调研数据库查询时因使用IEnumerable进行Linq to entity的操作,造成数据库访问缓慢.此文讲述的便是IEnumerable和IQueryable的区别. 微软对IEnumera ...
- Entity Framework返回IEnumerable还是IQueryable?
在使用EF的过程中,我们常常使用repository模式,本文就在repository层的返回值是IEnumerable类型还是IQueryable进行探讨. 阅读目录: 一.什么是Repositor ...
- EntityFramework中IEnumerable和IQueryable的含义和区别
先说下IList,IList对SQL语句是即时执行的,IEnumerable和IQueryable是延时执行的,用到才执行. IQueryable和IEnumerable在每次执行时都必须连接数据库读 ...
- 一个简单问题引发对IEnumerable和IQueryable的思考
问题概述: 首先看下图,有客户表和客户负责人表关系是多对多,访问数据库使用的是EF所以这里我们开启了延迟加载,需求就是将每个客户的所有负责人逗号拼接显示在负责人这一栏位, 对你没看错需求就是这么 ...
- List vs IEnumerable vs IQueryable vs ICollection vs IDictionary
目录 集合 数组 数组列表 哈希表 堆栈 队列 列表 IList 具体类与接口的区别 IEnumerable IQueryable SQL事件探查器 如何跟踪查询生成TSQL和将加载多少条记录: IC ...
- IEnumerable与IQueryable
共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable<T>的对象上运行.构成每组运算符的方法分别是 ...
- IEnumerable 与 IQueryable
无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable.Queryable,他们在System.Linq命名空间下.那么这两个类是如何定义的,又是 ...
最新文章
- 线程池运用不当的一次线上事故
- menuetos oracle,使用DistroTest服务免费在线测试Linux和Unix操作系统
- android 4.4 下拉菜单 透明,4.2状态栏,下拉,全局透明教程
- 终面后拿offer几率_面经 | 如愿以偿进入自己喜欢的游戏行业:我是怎样争取到理想OFFER的?...
- 不愧是我,短短10分钟就为公司省下了几万块 ( ー̀◡ー́ )
- 求贤令|诚邀3D视觉领域技术大咖加入工坊!
- poj-3034 Whac-a-Mole
- 7.11计划,做个没心没肺的人
- NoSQLAttack针对 mongoDB 的攻击工具
- 动手学数据分析之数据加载及探索性数据分析
- Wi-Fi:802.11ac new feature Beamforming
- Java常用关键字查询
- 简单的Java小游戏 -- 数字连连消
- 引用 JAVA面试题集
- lammps一对一课程学习大纲
- SDL应用之三种字库
- 程序员赚外快到底有哪些途径?干货篇
- Java云原生(Spring Native)开发初体验报告
- linux18.04安装显卡驱动,Ubuntu18.04安装nvidia显卡驱动
- VC 怎么获取windows7系统管理员权限