Language-Integrated 查询(LINQ)是基于将查询功能直接集成到 C# 语言的一组技术的名称。 传统上,针对数据的查询表示为简单字符串,无需在编译时进行类型检查或 IntelliSense 支持。 此外,必须了解每种数据源类型的不同查询语言:SQL 数据库、XML 文档、各种 Web 服务等。 使用 LINQ 时,查询是一流的语言构造,就像类、方法和事件一样。
编写查询时,LINQ 最明显的“语言集成”部分是查询表达式。 查询表达式以声明性 查询语法编写。 通过使用查询语法,可以使用最少的代码对数据源执行筛选、排序和分组作。 使用相同的查询表达式模式从任何类型的数据源查询和转换数据。
以下示例演示完整的查询操作。 完整的作包括创建数据源、定义查询表达式,以及执行语句中的 foreach
查询。
// Specify the data source.
int[] scores = [97, 92, 81, 60];
// Define the query expression.
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
// Execute the query.
foreach (var i in scoreQuery)
{
Console.Write(i + " ");
}
// Output: 97 92 81
可能需要为前面的示例添加 using
指令 using System.Linq;
,以便进行编译。 最新版本的 .NET 使用 隐式用法 将此指令添加为 全局用法。 旧版本要求您在源代码中添加它。
查询表达式概述
- 查询表达式从任何启用了 LINQ 的数据源查询和转换数据。 例如,单个查询可以从 SQL 数据库检索数据,并生成 XML 流作为输出。
- 查询表达式使用许多熟悉的 C# 语言构造,这使得它们易于阅读。
- 查询表达式中的变量都是强类型。
- 直到你对查询变量进行迭代,例如在
foreach
语句中,查询不会执行。 - 在编译时,查询表达式根据 C# 规范中定义的规则转换为标准查询运算符方法调用。 任何可以使用查询语法表示的查询也可以通过使用方法语法来表示。 在某些情况下,查询语法更易于阅读和简洁。 其他方法语法更具可读性。 这两种不同形式之间没有语义或性能差异。 有关详细信息,请参阅 C# 语言规范 和 标准查询运算符概述。
- 某些查询操作(如Count或Max)没有等效的查询表达式子句,因此必须通过方法调用来表达。 方法语法可以通过各种方式与查询语法结合使用。
- 查询表达式可被编译成表达式树或委托,具体视应用查询的类型而定。 IEnumerable<T> 查询编译为委托。 IQueryable 和 IQueryable<T> 查询编译为表达式树。 有关详细信息,请参阅 表达式树。
如何启用数据源的 LINQ 查询
内存中数据
可通过两种方式对内存中数据启用 LINQ 查询。 如果数据是实现 IEnumerable<T>的类型,则可以使用 LINQ to Objects 查询数据。 如果通过实现 IEnumerable<T> 接口来启用枚举没有意义,可以在该类型中定义 LINQ 标准查询运算符方法,也可以定义为该类型的扩展方法。 标准查询运算符的自定义实现应使用延迟执行返回结果。
远程数据
启用远程数据源 LINQ 查询的最佳选择是实现 IQueryable<T> 接口。
IQueryable LINQ 提供程序
实现 IQueryable<T> 的 LINQ 提供程序在复杂性上可能会有所不同。
不太复杂的 IQueryable
提供程序可能会从 Web 服务访问单个方法。 这种类型的提供程序非常具体,因为它需要它处理的查询中的特定信息。 它具有封闭类型系统,可能公开单个结果类型。 大多数查询的执行发生在本地,例如,使用 Enumerable 标准查询运算符的实现。 不太复杂的提供程序可能只检查表示查询的表达式树中的一个方法调用表达式,并允许在其他位置处理查询的剩余逻辑。
IQueryable
中等复杂性的提供程序可能以具有部分表达性查询语言的数据源为目标。 如果它面向 Web 服务,它可能会访问 Web 服务的多个方法,并根据查询查找的信息选择要调用的方法。 中等复杂性的提供程序具有比简单提供程序更丰富的类型系统,但它仍然是固定类型系统。 例如,提供程序可能会公开具有可遍历的一对多关系的类型,但它不会为用户定义的类型提供映射技术。
复杂 IQueryable
提供程序(如 Entity Framework Core 提供程序)可能会将完整的 LINQ 查询翻译为表达性查询语言,例如 SQL。 复杂的提供程序更为普遍,因为它可以处理查询中更广泛的问题。 它还具有开放类型系统,因此必须包含广泛的基础结构来映射用户定义的类型。 开发一个复杂的服务提供商需要付出大量的努力。