语⾔集成查询 (LINQ)

语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称。 数据查询历来都表示为简单的字符串,没有编译时类型检查或 IntelliSense 支持。 此外,需要针对每种类型的数据源了解不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等。 借助 LINQ,查询成为了最高级的语言构造,就像类、方法和事件一样。对于编写查询的开发者来说,LINQ 最明显的“语言集成”部分就是查询表达式。 查询表达式采用声明性 查询语法编写而成。 使用查询语法,可以用最少的代码对数据源执行筛选、排序和分组操作。 可使用相同的基本查询表达式模式来查询和转换 SQL 数据库、ADO .NET 数据集、XML 文档和流以及 .NET 集合中的数据。
下面的示例展示了完整的查询操作。 完整的操作包括创建数据源、定义查询表达式和在 foreach 语句中执行查询。
class LINQQueryExpressions { static void Main() { 
Specify the data source. int[] scores = new int[] { 97, 92, 81, 60 }; 
Define the query expression. IEnumerable<int> scoreQuery = from score in scores where score > 80 select score; 
Execute the query. foreach (int i in scoreQuery) { Console.Write(i + " "); 
}} }
// Output: 97 92 81
一.查询是什么及其作用是什么?
查询是一组指令,描述要从给定数据源(或源)检索的数据以及返回的数据应具有的形状和组织。 查询与它生成的结果不同。通常情况下,源数据按逻辑方式组织为相同类型的元素的序列。 例如,SQL 数据库表包含行的序列。 在 XML 文件中,存在 XML 元素的“序列”(尽管这些元素在树结构按层次结构进行组织)。 内存中集合包含对象的序列。从应用程序的角度来看,原始源数据的特定类型和结构并不重要。 应用程序始终将源数据视为 IEnumerable<T>或 IQueryable<T> 集合。 例如在 LINQ to XML 中,源数据显示为 IEnumerable <XElement>。
对于此源序列,查询可能会执行三种操作之一:
1.检索元素的子集以生成新序列,而不修改各个元素。 查询然后可能以各种方式对返回的序列进行排序或分组,如下面的示例所示(假定 scores 是 int[] ):
IEnumerable<int> highScoresQuery = 
from score in scores where score > 80
orderby score descending
select score;

2.如前面的示例所示检索元素的序列,但是将它们转换为新类型的对象。 例如,查询可以只从数据源中的某些客户记录检索姓氏。 或者可以检索完整记录,然后用于构造其他内存中对象类型甚至是 XML 数据,再生成最终的结果序列。 下面的示例演示从 int 到 string 的投影。 请注意 highScoresQuery 的新类型。

IEnumerable<string> highScoresQuery2 = 
from score in scores where score > 80
orderby score descending
select $"The score is {score}";

3.检索有关源数据的单独值,如:

与特定条件匹配的元素数。
具有最大或最小值的元素。
与某个条件匹配的第一个元素,或指定元素集中特定值的总和。 例如,下面的查询从 scores 整数数组返回大于 80 的分数的数量:
int highScoreCount =
(from score in scores
where score > 80
select score)
.Count();
在前面的示例中,请注意在调用 Count 方法之前,在查询表达式两边使用了括号。 也可以通过使用新变量存储具体结果,来表示此行为。 这种方法更具可读性,因为它使存储查询的变量与存储结果的查询分开。
IEnumerable<int> highScoresQuery3 = 
from score in scores where score > 80
select score;
int scoreCount = highScoresQuery3.Count();
在上面的示例中,查询在 Count 调用中执行,因为 Count 必须循环访问结果才能确定 highScoresQuery 返回的元素数。
二.查询表达式是什么?
查询表达式是以查询语法表示的查询。 查询表达式是一流的语言构造。 它如同任何其他表达式一样,可以在 C#表达式有效的任何上下文中使用。 查询表达式由一组用类似于 SQL 或 XQuery 的声明性语法所编写的子句组成。
每个子句进而包含一个或多个 C# 表达式,而这些表达式可能本身是查询表达式或包含查询表达式。查询表达式必须以 from 子句开头,且必须以 select 或 group 子句结尾。 在第一个 from 子句与最后一个select 或 group 子句之间,可以包含以下这些可选子句中的一个或多个:where、orderby、join、let,甚至是其他 from 子句。 还可以使用 into 关键字,使 join 或 group 子句的结果可以充当相同查询表达式中的其他查询子句的源。
 
查询变量
在 LINQ 中,查询变量是存储查询而不是查询结果的任何变量。 更具体地说,查询变量始终是可枚举类型,在foreach 语句或对其 IEnumerator.MoveNext 方法的直接调用中循环访问时会生成元素序列。下面的代码示例演示一个简单查询表达式,它具有一个数据源、一个筛选子句、一个排序子句并且不转换源元素。 该查询以 select 子句结尾
static void Main() { 
    // Data source. 
    int[] scores = { 90, 71, 82, 93, 75, 82 }; 
    // Query Expression. 
    IEnumerable<int> scoreQuery = //query variable 
    from score in scores //required 
    where score > 80 // 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 是查询变量,它有时仅仅称为查询。 查询变量不存储在 foreach 循环生成中的任何实际结果数据。 并且当 foreach 语句执行时,查询结果不会通过查询变量 scoreQuery 返回。 而是通过迭代变量 testScore 返回。 scoreQuery 变量可以在另一个 foreach 循环中进行循环访问。 只要既没有修改它,也没有修改数据源,便会生成相同结果。
查询变量可以存储采用查询语法、方法语法或是两者的组合进行表示的查询。 在以下示例中, queryMajorCities和 queryMajorCities2 都是查询变量:
//Query syntax 
IEnumerable<City> queryMajorCities = 
from city in cities where city.Population > 100000 
select city; 
// Method-based syntax 
IEnumerable<City> queryMajorCities2 = 
cities.Where(c => c.Population > 100000);
另一方面,以下两个示例演示不是查询变量的变量(即使各自使用查询进行初始化)。 它们不是查询变量,因为它们存储结果:
int highestScore = (from score in scores select score).Max(); 
// or split the expression 
IEnumerable<int> scoreQuery = from score in scores select score; 
int highScore = scoreQuery.Max(); 
// the following returns the same result int highScore = scores.Max(); 
List<City> largeCitiesList = 
(from country in countries from city in country.Cities 
where city.Population > 10000 select city).ToList(); 
//or split the expression 
IEnumerable<City> largeCitiesQuery = 
from country in countries from city in country.Cities 
where city.Population > 10000 select city; 
List<City> largeCitiesList2 = largeCitiesQuery.ToList();
查询变查的显式和隐式类型化
本文档通常提供查询变量的显式类型以便显示查询变量与 select 子句之间的类型关系。 但是,还可以使用 var 关
键字指示编译器在编译时推断查询变量(或任何其他局部变量)的类型。 例如,本主题中前面演示的查询示例也
可以使用隐式类型化进行表示:
// Use of var is optional here and in all queries. 
// queryCities is an IEnumerable<City> just as
// when it is explicitly typed. 
var queryCities = 
from city in cities 
where city.Population > 100000 
select city;

三.使用“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 >= 20
orderby countryGroup.Key
select countryGroup;
 
筛选、排序和、联接
在开头 from 子句与结尾 select 或 group 子句之间,所有其他子句( where 、 join 、 orderby 、 from 、 let )
都是可选的。 任何可选子句都可以在查询正文中使用零次或多次。
where子句
IEnumerable<City> queryCityPop = 
from city in cities 
where city.Population < 200000 && city.Population > 100000 
select city;

orderby子句

IEnumerable<Country> querySortedCountries = 
from country in countries 
orderby country.Area, country.Population descending //ascending 关键字是可选的;如果未指定任何顺序,则它是默认排序顺序
select country;

join子句

使用 join 子句可基于每个元素中指定的键之间的相等比较,将一个数据源中的元素与另一个数据源中的元素
进行关联和/或合并。
var categoryQuery = 
from cat in categories join prod in products on cat equals prod.Category 
select new { Category = cat, Name = prod.Name };

let子句

使用 let 子句可将表达式(如方法调用)的结果存储在新范围变量中。
string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" }; 
IEnumerable<string> queryFirstNames = 
from name in names let firstName = name.Split(' ')[0] 
select firstName; 
foreach (string s in queryFirstNames) 
Console.Write(s + " ");
//Output: Svetlana Claire Sven Cesar

 

 
posted @ 2022-04-11 15:56  Tammytan  阅读(76)  评论(0编辑  收藏  举报