一、LINQ查询的数据源

  从应用程序的角度来看,原始源数据的特定类型和结构并不重要。 应用程序始终将源数据视为 IEnumerable<T> 或 IQueryable<T> 集合。

例如在 LINQ to XML 中,源数据显示为 IEnumerable<XElement>。所以要对某个对象应用LINQ查询,该对象必须实现 IEnumerable<T> 或 IQueryable<T> 。

  其中,数组类型并为实现 IEnumerable<T> 或 IQueryable<T> ,为什么也可进行LINQ查询呢?

二、查询可能会执行三种操作

  • 检索元素的子集以生成新序列,而不修改各个元素。 查询然后可能以各种方式对返回的序列进行排序或分组,如下面的示例所示(假定 scores 是 int[]):
IEnumerable<int> highScoresQuery = from score in scores where score >  orderby score descending select score;
  • 如前面的示例所示检索元素的序列,但是将它们转换为新类型的对象。 例如,查询可以只从数据源中的某些客户记录检索姓氏。或者可以检索完整记录,然后用于构造其他内存中对象类型甚至是 XML 数据,再生成最终的结果序列。 下面的示例演示从 int到 string 的投影。 请注意 highScoresQuery 的新类型。
IEnumerable<string> highScoresQuery2 =
from score in scores
where score >
orderby score descending
select $"The score is {score}";
  • 检索有关源数据的单独值,如:
    • 与特定条件匹配的元素数。

    • 具有最大或最小值的元素。

    • 与某个条件匹配的第一个元素,或指定元素集中特定值的总和。 例如,下面的查询从 scores 整数数组返回大于 80 的分数的数量:

int highScoreCount =
(from score in scores
where score >
select score)
.Count();

在前面的示例中,请注意在调用 Count 方法之前,在查询表达式两边使用了括号。 也可以通过使用新变量存储具体结果,来表示此行为。 这种方法更具可读性,因为它使存储查询的变量与存储结果的查询分开。

IEnumerable<int> highScoresQuery3 =
from score in scores
where score >
select score; int scoreCount = highScoresQuery3.Count();

三、查询表达式

查询表达式必须以 from 子句开头,且必须以 select 或 group 子句结尾。在第一个 from 子句与最后一个 select 或 group 子句之间,可以包含以下这些可选子句中的一个或多个:whereorderbyjoinlet,甚至是其他 from 子句。 还可以使用 into 关键字,使 join 或 group 子句的结果可以充当相同查询表达式中的其他查询子句的源。

下面的代码示例演示一个简单查询表达式,它具有一个数据源、一个筛选子句、一个排序子句并且不转换源元素。 该查询以 select子句结尾。

static void Main()
{
// Data source.
int[] scores = { , , , , , }; // Query Expression.
IEnumerable<int> scoreQuery = //query variable
from score in scores //required
where score > // optional
orderby score descending // optional
select score; //must end with select or group // Execute the query to produce the results
foreach (int testScore in scoreQuery)
{
Console.WriteLine(testScore);
}
}
// Outputs: 93 90 82 82

查询变量

在上面的示例中,scoreQuery 是查询变量,它有时仅仅称为查询。查询变量可以存储采用查询语法、方法语法或是两者的组合进行表示的查询,而不是查询的结果。

开始查询表达式

查询表达式必须以 from 子句开头。 它指定数据源以及范围变量。 范围变量表示遍历源序列时,源序列中的每个连续元素。 范围变量基于数据源中元素的类型进行强类型化。 在下面的示例中,因为 countries 是 Country 对象的数组,所以范围变量也类型化为 Country。 因为范围变量是强类型,所以可以使用点运算符访问该类型的任何可用成员。

IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > //sq km
select country;

范围变量一直处于范围中,直到查询使用分号或 continuation 子句退出。

查询表达式可能会包含多个 from 子句。 在源序列中的每个元素本身是集合或包含集合时,可使用其他 from 子句。 例如,假设具有 Country 对象的集合,其中每个对象都包含名为 Cities 的 City 对象集合。 若要查询每个 Country 中的 City 对象,请使用两个 from 子句,如下所示:

IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population >
select city;

结束查询表达式

查询表达式必须以 group 子句或 select 子句结尾。

group 子句

使用 group 子句可生成按指定键组织的组的序列。 键可以是任何数据类型。 例如,下面的查询会创建包含一个或多个 Country 对象并且其键是 char 值的组的序列。

var queryCountryGroups =
from country in countries
group country by country.Name[];

select 子句

使用 select 子句可生成所有其他类型的序列。 简单 select 子句只生成类型与数据源中包含的对象相同的对象的序列。 在此示例中,数据源包含 Country 对象。 orderby 子句只按新顺序对元素进行排序,而 select 子句生成重新排序的 Country 对象的序列。

IEnumerable<Country> sortedQuery =
from country in countries
orderby country.Area
select country;

select 子句可以用于将源数据转换为新类型的序列。 此转换也称为投影。 在下面的示例中,select 子句对只包含原始元素中的字段子集的匿名类型序列进行投影。 请注意,新对象使用对象初始值设定项进行初始化。

// Here var is required because the query
// produces an anonymous type.
var queryNameAndPop =
from country in countries
select new { Name = country.Name, Pop = country.Population };

使用“into”进行延续

可以在 select 或 group 子句中使用 into 关键字创建存储查询的临时标识符。 如果在分组或选择操作之后必须对查询执行其他查询操作,则可以这样做。 在下面的示例中,countries 按 1000 万范围,根据人口进行分组。 创建这些组之后,附加子句会筛选出一些组,然后按升序对组进行排序。 若要执行这些附加操作,需要由 countryGroup 表示的延续。

// percentileQuery is an IEnumerable<IGrouping<int, Country>>
var percentileQuery =
from country in countries
let percentile = (int) country.Population / 10_000_000
group country by percentile into countryGroup
where countryGroup.Key >=
orderby countryGroup.Key
select countryGroup; // grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
Console.WriteLine(grouping.Key);
foreach (var country in grouping)
Console.WriteLine(country.Name + ":" + country.Population);
}

筛选、排序和联接

在开头 from 子句与结尾 select 或 group 子句之间,所有其他子句(wherejoinorderbyfromlet)都是可选的。任何可选子句都可以在查询正文中使用零次或多次。

where 子句

使用 where 子句可基于一个或多个谓词表达式,从源数据中筛选出元素。 以下示例中的 where 子句具有一个谓词及两个条件。

IEnumerable<City> queryCityPop =
from city in cities
where city.Population < && city.Population >
select city;

orderby 子句

使用 orderby 子句可按升序或降序对结果进行排序。 还可以指定次要排序顺序。 下面的示例使用 Area 属性对 country 对象执行主要排序。 然后使用 Population 属性执行次要排序。

IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;

ascending 关键字是可选的;如果未指定任何顺序,则它是默认排序顺序。

join 子句

使用 join 子句可基于每个元素中指定的键之间的相等比较,将一个数据源中的元素与另一个数据源中的元素进行关联和/或合并。在 LINQ 中,联接操作是对元素属于不同类型的对象序列执行。 联接了两个序列之后,必须使用 select 或 group 语句指定要存储在输出序列中的元素。 还可以使用匿名类型将每组关联元素中的属性合并到输出序列的新类型中。 下面的示例关联其 Category 属性与 categories 字符串数组中一个类别匹配的 prod 对象。 筛选出其 Category 不与 categories 中的任何字符串匹配的产品。select 语句会投影其属性取自 cat 和 prod 的新类型。

var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new { Category = cat, Name = prod.Name };

还可以通过使用 into 关键字将 join 操作的结果存储到临时变量中来执行分组联接。

let 子句

使用 let 子句可将表达式(如方法调用)的结果存储在新范围变量中。 在下面的示例中,范围变量 firstName 存储 Split 返回的字符串数组的第一个元素。

string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" };
IEnumerable<string> queryFirstNames =
from name in names
let firstName = name.Split(' ')[]
select firstName; foreach (string s in queryFirstNames)
Console.Write(s + " ");
//Output: Svetlana Claire Sven Cesar

查询表达式中的子查询

查询子句本身可能包含查询表达式,这有时称为子查询。 每个子查询都以自己的 from 子句开头,该子句不一定指向第一个 from子句中的相同数据源。 例如,下面的查询演示在 select 语句用于检索分组操作结果的查询表达式。

var queryGroupMax =
from student in students
group student by student.GradeLevel into studentGroup
select new
{
Level = studentGroup.Key,
HighestScore =
(from student2 in studentGroup
select student2.Scores.Average())
.Max()
};

LINQ-查询表达式基础的更多相关文章

  1. LINQ查询表达式基础

    LINQ,语言集成查询(Language Integrated Query)是一组用C#和Visual Basic语言的扩展. 对于编写查询的开发人员来说,LINQ 最明显的"语言集成&qu ...

  2. LINQ查询表达式(1) - 查询表达式基础

    LINQ包括五个部分:LINQto Objects.LINQ to DataSets.LINQ to SQL.LINQ to Entities.LINQ to XML. 什么是查询?它有什么用途? “ ...

  3. Linq专题之创建Linq查询表达式

    本节我们主要介绍一下如何创建查询集合类型,关系数据库类型,DataSet对象类型和XML类型的数据源的Linq查询表达式. 下面在实例代码ReadyCollectionData()函数创建了准备的数据 ...

  4. 2.3 LINQ查询表达式中 使用select子句 指定目标数据

    本篇讲解LINQ查询的三种形式: 查询对象 自定义查询对象某个属性 查询匿名类型结果 [1.查询结果返回集合元素] 在LINQ查询中,select子句和from子句都是必备子句.LINQ查询表达式必须 ...

  5. LINQ查询表达式---------let子句

    LINQ查询表达式---------let子句 let子句创建一个范围变量来存储结果,变量被创建后,不能修改或把其他表达式的结果重新赋值给它.此范围变量可以再后续的LINQ子句中使用. class P ...

  6. LINQ查询表达式---------join子句

    LINQ查询表达式---------join子句 join 子句接受两个源序列作为输入. 每个序列中的元素都必须是可以与另一个序列中的相应属性进行比较的属性,或者包含一个这样的属性. join子句使用 ...

  7. LINQ查询表达式---------orderby子句

    LINQ查询表达式---------orderby子句 LINQ可以按元素的一个或多个属性对元素进行排序. class Program { public class PerInfo { public ...

  8. LINQ查询表达式---------into

    LINQ查询表达式---------into into 上下文关键字创建一个临时标识符,以便将 group.join 或 select 子句的结果存储到新的标识符 class Program { pu ...

  9. LINQ查询表达式---------group子句

    LINQ查询表达式---------group子句 LINQ表达式必须以from子句开头,以select或group子句结束.使用guoup子句来返回元素分组后的结果.group 子句返回一个 IGr ...

  10. LINQ查询表达式---------select子句

    LINQ查询表达式---------select子句 1.1常见的select子句查询 class Program { public class PerInfo { public int Id { g ...

随机推荐

  1. eCharts基础知识

    eCharts插件介绍 http://echarts.baidu.com/tutorial.html#ECharts%20%E7%89%B9%E6%80%A7%E4%BB%8B%E7%BB%8D

  2. 2019/05/11 JAVA虚拟机原理

    所谓虚拟机,就是一台虚拟的机器.他是一款软件,用来执行一系列虚拟计算指令,大体上虚拟机可以分为 系统虚拟机和程序虚拟机, 大名鼎鼎的Visual Box.Vmare就属于系统虚拟机,他们完全是对物理计 ...

  3. ios 自定义消息提示框

    自定义提示框,3秒钟后自动消失.如上图显示效果. 提示框加载代码: - (void)viewDidLoad { [super viewDidLoad]; //将view背景颜色变更为黄色 self.v ...

  4. run_test() 验证平台的入口

    Run,just run!    ——阿甘正传   一个简单的例子: module tb_top; dut u_dut (); initial begin run_test(); end config ...

  5. SIT&UAT

  6. python 相关编码[转]

    python 相关编码[转]   三篇文章,导航:(一)(二)(三) (一) 怎么避免UnicodeEncodeError: ‘ascii’ codec can’t…类似的错误? 1.首先在py文件头 ...

  7. Spring IOC模块的简单介绍

    首先,本人正在学习spring,这是一点心得体会,所以本文中会有不足.错误之处,欢迎各位大佬进行指点. 其次对于框架而言,知道反射是很重要,所以建议在学会反射了后在去看看框架. Spring:是企业级 ...

  8. java 核心技术卷一笔记 6 .2接口 lambda 表达式 内部类

    6.2 接口实例 6.2.1 接口与回调 在java.swing包中有一个Timer类,可以使用它在到达给定的时间间隔时发出通告,假如程序中有一个时钟,就可以请求每秒钟获得一个通告,以便更新时钟的表盘 ...

  9. Python之Mac Scrapy爬虫小记

    最近在尝试用Python爬虫,在装Scrapy的过程中遇到了一些麻烦. 上网搜索资料也未能解决command not found scrapy的报错. 最后我删除scrapy,用pip3.6 inst ...

  10. HDU 4348 I - To the moon 可持续化

    队友套的可持续化线段树,徘徊在RE和MLE之间多发过的... 复用结点新的线段树平均要log2N个结点. 其实离线就好,按照时间顺序组织操作然后dfs. #include <iostream&g ...