当前位置: 澳门新濠3559 > 编程 > 正文

  查询是一种从数据源检索数据的表达式, 

时间:2019-11-07 12:30来源:编程
1、C#中LINQ to Objects中延迟查询的陷阱(其他类型的LINQ也基本一致) 查询是一种从数据源检索数据的表达式。查询通常用专门的查询语言来表示。随着时间的推移,人们已经为各种数据

1、C#中LINQ to Objects中延迟查询的陷阱(其他类型的LINQ也基本一致)

  查询是一种从数据源检索数据的表达式。查询通常用专门的查询语言来表示。随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。LINQ 通过提供一种跨各种数据源和数据格式使用数据的一致模型,简化了这一情况。在 LINQ 查询中,始终会用到对象。可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。

之前在不了解LINQ延迟查询的时候,我使用下面的这种方式,将where语句的结果直接as为List<T>对象,结果得到的temp为NULL,苦思不得其解;

  查询操作的三个部分

List<person> lst = new List<person>(){
    new person(){id=1,name="cyong"},
    new person(){id=2,name="lshan"}
};
List<person> temp = lst.Where(m => m.id > 1) as List<person>;

  所有 LINQ 查询操作都由以下三个不同的操作组成:

 

  1、获取数据源。

求解思路:

  2、创建查询。

  一开始以为是LINQ语句的问题,但是在反复测试之后,发现 lst.Where(m => m.id > 1) 确实是语法正确的,并且能够在调用ToList()扩展方法后返回正确的结果集;

  3、执行查询。  

  而后,考虑是as的问题,查看as的使用方式,发现as是类型安全的转换方式,当转换失败时不会报错,而是返回null;但是查看文档发现Where语句返回的是IEnumerable<TSource>,而IEnumerable<T>在一般情况下(比如我先将一个List<T>转换为IEnumerable<T>,再通过一次as转换回来)是可以正常转换为List<T>的;

  下面的示例演示如何用源代码表示查询操作的三个部分。为方便起见,此示例将一个整数数组用作数据源;但其中涉及的概念同样适用于其他数据源。本主题的其余部分也会引用此示例。

求助:

澳门新濠3559 1澳门新濠3559 2Code
 1澳门新濠3559 3using System;
 2澳门新濠3559 4using System.Collections.Generic;
 3澳门新濠3559 5using System.Linq;
 4澳门新濠3559 6using System.Text;
 5澳门新濠3559 7
澳门新濠3559, 6澳门新濠3559 8namespace LINQDemo2
 7澳门新濠3559 9澳门新濠3559 10澳门新濠3559 11{
 8澳门新濠3559 12    class Program
 9澳门新濠3559 13澳门新濠3559 14  查询是一种从数据源检索数据的表达式,  一开始以为是LINQ语句的问题。    澳门新濠3559 15{
10澳门新濠3559 16        static void Main(string[] args)
11澳门新濠3559 17澳门新濠3559 18        澳门新濠3559 19{
12澳门新濠3559 20            //int[] numbers = new int[] { 0, 1, 2, 3, 4, 5, 6 };
13澳门新濠3559 21
14澳门新濠3559 22            //var query = from num in numbers
15澳门新濠3559 23            //            where (num % 2 ) == 1
16澳门新濠3559 24            //            select num;
17澳门新濠3559 25            //foreach (int num in query)
18澳门新濠3559 26            //{
19澳门新濠3559 27            //    Console.WriteLine("{0,1}",num);
20澳门新濠3559 28            //}
21澳门新濠3559 29
22澳门新濠3559 30            // The Three Parts of a LINQ Query:
23澳门新濠3559 31            //  1. Data source.
24澳门新濠3559 32澳门新濠3559 33            string[] strArray = new string[] 澳门新濠3559 34{ "fine","Thank","you","Hello","World" };
25澳门新濠3559 35
26澳门新濠3559 36            // 2. Query creation.
27澳门新濠3559 37            // numQuery is an IEnumerable<int>
28澳门新濠3559 38            var stringQuery = from str in strArray
29澳门新濠3559 39                              where str.Length == 5
30澳门新濠3559 40                              select str;
31澳门新濠3559 41            // 3. Query execution.
32澳门新濠3559 42            foreach (string s in stringQuery)
33澳门新濠3559 43澳门新濠3559 44            澳门新濠3559 45{
34澳门新濠3559 46                Console.WriteLine("{0,1}", s);
35澳门新濠3559 47            }
36澳门新濠3559 48        }
37澳门新濠3559 49    }
38澳门新濠3559 50}

  然后就将这个问题抛给了群里面的一群大神。经过一番指点,才发现这个问题的缘由是LINQ的懒加载(延迟查询)。

 

  上文档:

  下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变量,则不会检索任何数据。

  LINQ查询简介

澳门新濠3559 51

  文档中介绍到【查询变量本身只存储查询命令。查询的实际执行将推迟到“foreach”语句中循环访问查询变量之后进行;同时,也可以通过ToList或者ToArray方法强制立即执行,以将查询结果缓存到单个集合对象中】

  在上一个示例中,由于数据源是数组,因此它隐式支持泛型 IEnumerable<(Of <(T>)>) 接口。这一事实意味着该数据源可以用 LINQ 进行查询。在 foreach 语句中执行查询,而 foreach 要求使用 IEnumerable 或 IEnumerable<(Of <(T>)>)。支持 IEnumerable<(Of <(T>)>) 或派生接口(如泛型 IQueryable<(Of <(T>)>))的类型称为“可查询类型”。

  Enumerable.Where<TSource>方法(IEnumerable<TSource>,Func<TSource,Int32,Boolean>).aspx)

  可查询类型不需要进行修改或特殊处理就可以用作 LINQ 数据源。如果源数据还没有作为可查询类型出现在内存中,则 LINQ 提供程序必须以此方式表示源数据。

  此方法使用的是LINQ的延迟查询。

  上一个示例中的查询从整数数组中返回所有偶数。该查询表达式包含三个子句:from、where 和 select。(如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。)from 子句指定数据源,where 子句应用筛选器,select 子句指定返回的元素的类型。LINQ 查询表达式(C# 编程指南)一节中详细讨论了这些子句和其他查询子句。目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。

结论:

  

  1、LINQ查询只是缓存查询命令,要访问查询结果,应该使用foreach去迭代或者使用ToList()或者ToArray方法强制立即执行并缓存到集合对象中。

  延迟执行

  如前所述,查询变量本身只是存储查询命令。实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。此概念称为“延迟执行”。  

  由于查询变量本身从不保存查询结果,因此可以根据需要随意执行查询。例如,可以通过一个单独的应用程序持续更新数据库。在应用程序中,可以创建一个检索最新数据的查询,并可以按某一时间间隔反复执行该查询以便每次检索不同的结果。

  强制立即执行
  对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。Count、Max、Average 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。下面的查询返回源数组中偶数的计数:  

澳门新濠3559 52var evenNumQuery = 
澳门新濠3559 53    from num in numbers
澳门新濠3559 54    where (num % 2) == 0
澳门新濠3559 55    select num;
澳门新濠3559 56
澳门新濠3559 57int evenNumCount = evenNumQuery.Count();

  若要强制立即执行任意查询并缓存其结果,可以调用 ToList<(Of <(TSource>)>) 或 ToArray<(Of <(TSource>)>) 方法。

澳门新濠3559 58澳门新濠3559 59Code
澳门新濠3559 60List<int> numQuery2 =
澳门新濠3559 61    (from num in numbers
澳门新濠3559 62     where (num % 2) == 0
澳门新濠3559 63     select num).ToList();
澳门新濠3559 64
澳门新濠3559 65// or like this:
澳门新濠3559 66// numQuery3 is still an int[]
澳门新濠3559 67
澳门新濠3559 68var numQuery3 =
澳门新濠3559 69    (from num in numbers
澳门新濠3559 70     where (num % 2) == 0
澳门新濠3559 71     select num).ToArray();

  此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。但是,通过调用 ToListToArray,也可以将所有数据缓存在单个集合对象中。

 

  2、MSDN文档不得不看看。

附图:

  1、同行指教

澳门新濠3559 72

澳门新濠3559 73

 

编辑:编程 本文来源:  查询是一种从数据源检索数据的表达式, 

关键词: