延迟执行的经典例子

我们用 select ++i 就可以看到在foreach 时候,查询才被执行。

public static void Linq99()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = from n in numbers select ++i;
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

输出结果:

v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10

foreach每一个遍历的时候,select出来的值和当前i的值都是一样的。

立即执行的经典例子:

public static void Linq99()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = (from n in numbers select ++i).ToList();
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

执行结果:

v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10

这个例子的代码跟上面延迟执行的例子代码唯一的差别在于多了一个.ToList();
这也可以证明我们之前提到的原则:

只有到用的时候才会去执行查询

由于 .ToList(); 的存在,在这里就要用到了,所以在这里就执行了查询,而不是在foreach中执行查询。注意,这时候出来的结果是一个数组了.参看后面的几个例子.

执行的一个特殊情况:重复执行

请看下面例子:

查询出一个int数组中小于3的数字。

下面例子中在第一次查询后,对数据源作了修改,然后再作第二次查询,我们可以看到第二次我们不需要再作

lowNumbers = from n in numbers where n <= 3 select n; 这样的定义,而是直接使用    foreach (int n in lowNumbers)。另外这两次的返回结果是不同的,因为我们
在第一次查询后,对数据源作了修改。

public static void Linq101()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    var lowNumbers = from n in numbers where n <= 3 select n;
    Console.WriteLine(“First run numbers <= 3:”);
    foreach (int n in lowNumbers)
        Console.WriteLine(n);

for (int i = 0; i < 10; i++)
        numbers[i] = -numbers[i];

Console.WriteLine(“Second run numbers <= 3:”);
    foreach (int n in lowNumbers)
        Console.WriteLine(n);
}

输出结果:

First run numbers <= 3:
1
3
2
0
Second run numbers <= 3:
-5
-4
-1
-3
-9
-8
-6
-7
-2
0

以上三个例子均来自 101 LINQ Samples

下面我们再来看几个例子,加深对查询执行的理解:

重复查询的再一个例子:

public static void Linq102()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = from n in numbers select ++i;
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

执行结果:

v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10
v = 11, i = 11
v = 12, i = 12
v = 13, i = 13
v = 14, i = 14
v = 15, i = 15
v = 16, i = 16
v = 17, i = 17
v = 18, i = 18
v = 19, i = 19
v = 20, i = 20

只执行一次的立即查询:

public static void Linq102()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = (from n in numbers select ++i).ToList();
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

执行结果:

v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10

那些函数会导致立即执行查询:

以下几个扩展函数会导致LINQ会立即执行。并且只执行一次。

.ToArray();

.ToList();

.ToDictionary(k => k);

比如:

public static void Linq102()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = (from n in numbers select ++i).ToDictionary(k => k);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

输出结果就是:

v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10

小结:

Q:通过上面几个例子,我们该如何理解LINQ的查询何时执行呢?

A:LINQ的查询执行遵循以下原则:

1、一般情况下(除了下面第三条说的情况),LINQ都是延迟执行,原因:以DLINQ为例,越晚被执行,对业务逻辑的理解就越清晰,DLINQ查询对数据库的请求压力越小。编译器对LINQ查询优化可作的事情越多。

2、由于是延迟执行,也就是调用的时候才去执行。这样调用一次就被执行一次,这样就具备了重复执行的功能,参看之前的几个重复执行的例子。而这个重复执行是不需要再此书写一边查询语句的。

3、如果查询中我们对查询结果使用了 ToArray、ToList、ToDictionary 这些转换成集合的扩展方法。使用这时候出来的对象是一个独立的集合数组,而不是LINQ查询,所以这时候不会出现多次查询,而只是一次查询。

即:var q = from n in numbers select ++i ;  这样一条语句我们可以认为它记录的不是等号右边的结果,而是记录的等号右边的表达式。

而    var q = (from n in numbers select ++i).ToDictionary(k => k); 这样一条语句我们记录的是等号右边的计算结果,而不是表达式。

为理解上面说明,我们可以再看两个例子:

public static void Linq102()
{
    int[] numbers = new int[] { 5,
4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = from n in numbers select ++i;
    var qq = q.ToDictionary(k => k);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
    foreach (var v in q)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

输出结果:

v = 11, i = 11
v = 12, i = 12
v = 13, i = 13
v = 14, i = 14
v = 15, i = 15
v = 16, i = 16
v = 17, i = 17
v = 18, i = 18
v = 19, i = 19
v = 20, i = 20
v = 21, i = 21
v = 22, i = 22
v = 23, i = 23
v = 24, i = 24
v = 25, i = 25
v = 26, i = 26
v = 27, i = 27
v = 28, i = 28
v = 29, i = 29
v = 30, i = 30

public static void Linq102()
{
    int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int i = 0;
    var q = from n in numbers select ++i;
    var qq = q.ToDictionary(k => k);
    foreach (var v in qq)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
    foreach (var v in qq)
        Console.WriteLine(“v = {0}, i = {1}”, v, i);
}

输出结果为:

v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10

LINQ 的查询执行何时是延迟执行,何时是立即执行,以及查询的复用相关推荐

  1. go mysql 查询语句_01 MySQL-初识MySQL-查询语句的执行流程-Go语言中文社区

    MySQL的基础架构 我们通过一条查询语句来看看MySQL是如何执行的,同时通过这条语句的执行,了解MySQL的整体架构体系.mysql> select * from T where ID=1: ...

  2. oracle trigger 延迟执行_一文详解Spring任务执行和调度

    一.概述 Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象.Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境 ...

  3. sqlserver 参数化查询 允许为null_关于SQL Server的insert执行的秘密(上)一个最简单的insert分析...

    准备工作: 我需要一张User表,这张表有几个字段,还有一个自增长的数字id,表结构如下: 这是一张比现实应用中简单的多的用户表,UserID是自增长字段. 开始执行一个最简单的INSERT: INS ...

  4. OceanBase SQL 执行计划解读(二)──── 表连接和子查询

    前文<OceanBase SQL 执行计划解读(一)>介绍了单表查询中基本的执行计划解读,本文主要介绍简单的表连接和子查询相关的执行计划. 本文假设你对常用的表连接算法已有了解,包括:嵌套 ...

  5. bat如何执行完上一条命令_一条SQL查询语句是如何执行的?

    本篇文章将通过一条 SQL 的执行过程来介绍 MySQL 的基础架构. 首先有一个 user_info 表,表里有一个 id 字段,执行下面这条查询语句: select * from user_inf ...

  6. oracle当查询没有输出返回0,Oracle导入SQL脚本执行和常用命令大全

    在SQL_PLUS里面执行: sql>@full_path/test.sql; 例:sql>@D:/test.sql; 不需要commit; 一般都是在test.sql 里面最后加上一个c ...

  7. Linux学习笔记39——任务调度:什么是例行性工作调度、仅执行一次的工作调度、循环执行的例行性工作调度、可唤醒停机期间的工作任务

    一.什么是例行性工作调度 1,Linux 工作调度的种类: at, cron 2,CentOS Linux 系统上常见的例行性工作 二,仅执行一次的工作调度 1,atd 的启动与 at 运行的方式 a ...

  8. mysql执行事务的语句_详解MySQL执行事务的语法和流程

    摘要:MySQL 提供了多种存储引擎来支持事务. MySQL 提供了多种存储引擎来支持事务.支持事务的存储引擎有 InnoDB 和 BDB,其中,InnoDB 存储引擎事务主要通过 UNDO 日志和 ...

  9. mybatisplus执行sql语句_[MySQL]sql语句的执行流程

    此篇极客时间专栏<MySQL实战45讲>笔记,文中部分图文来自该专栏. MySQL的执行流程示意图: 大体来说,MySQL可以分为Server层和存储引擎层两部分. Server层包括连接 ...

  10. 每次执行java命令 都要source_解决每次执行Java等命令时都要重新source /etc/profile后才能执行,否则找不到命令...

    linux mint 我们通常将环境变量设置在/etc/profile这个文件中,这个文件是全局的. /etc/profile:在登录时,操作系 统定制用户环境时使用的第一个文件 ,此文件为系统的每个 ...

最新文章

  1. AOP实现Controller参数日志
  2. django model
  3. DIY服务器配置全方位详解
  4. taskspawn函数 linux,vxworks的启动任务taskSpawn
  5. android照片编辑软件,照片编辑免费软件下载-照片编辑软件app下载 v7.45最新版_5577安卓网...
  6. linux允许所有用户执行文件夹,在Linux中,可以使用命令()针对文件newfiles.txt为所有用户添加执行权限。...
  7. Swift多线程:GCD进阶,单例、信号量、任务组
  8. python语音属于什么语言_python到底是什么类型的语言
  9. STm32驱动74HC595引脚图时序图工作原理
  10. Recyclerview-BRVAH使用
  11. 十分钟打造 3D 物理世界
  12. Flash CS3:FLV视频短片我来做!
  13. 0元参会丨第十届数据技术嘉年华精彩抢先速览
  14. 关于一个web网站的欢迎页面
  15. Android开发实战《手机安全卫士》——6.“高级工具”模块拓展 自定义Toast
  16. 什么是开发平台? 几句话就让你明白!
  17. 华为手机锁屏下拉怎么设置_华为手机怎么设置会滚动的锁屏文字?设置步骤超简单,一看就会...
  18. 一个简单的购物商城,记录一下。
  19. JavaScript知识点 总结二:
  20. 高通的熔丝(Blow eFuse)操作

热门文章

  1. 异常与锁的释放(synchronized )
  2. uniGUI试用笔记(一)
  3. 缓存使用-4、Redis 持久化机制
  4. 手机端适配rem计算方法
  5. CSS padding
  6. 转:UniqueID和ClientID的来源
  7. Asp.Net Web API 2第七课——Web API异常处理
  8. 也谈ASP.NET页面事件
  9. Sourcing Cockpit: 2. Demo of Service Purchase Order
  10. 创造包容的环境和上升空间