.NET LINQ概述
- LINQ
语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,它在对象领域和数据领域之间架起了一座桥梁。可为 C# 和 Visual Basic 语言语法提供强大的查询功能。 LINQ 引入了标准、易学的数据查询和更新模式,该技术可以扩展为几乎支持任何类型的数据存储。Visual Studio 包含 LINQ 提供程序的程序集,借助这些程序集,就能将 LINQ 用于 .NET Framework 集合、SQL Server 数据库、ADO.NET 数据集和 XML 文档。
- LINQ应用场景
-
- LINQ to Object:针对数组和集合
- LINQ to XML:针对XML文档
- LINQ to DataSet:针对ADO的DataSet对象
- LINQ to Entites:针对EF
- Parallel LINQ:并行处理LINQ查询返回的数据
- LINQ 查询
查询是一种从数据源检索数据的表达式。 查询通常用专门的查询语言来表示。 随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。 因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。 LINQ 通过提供一种跨各种数据源和数据格式使用数据的一致模型,简化了这一情况。 在 LINQ 查询中,始终会用到对象。 可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。
-
- 获取数据源
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
|
-
- 创建查询
-
- 执行查询
-
- 延迟执行
查询变量本身只是存储查询命令。实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。此概念称为“延迟执行”
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
|
-
-
- 强制立即执行
-
对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。 Count、Max、Average 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。
var evenNumQuery =
from num in numbers
where (num % 2) == 0
select num;
int evenNumCount = evenNumQuery.Count();
|
若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法。
List<int> numQuery2 =
(from num in numbers
where (num % 2) == 0
select num).ToList();
|
- 支持 LINQ 的功能
-
- 查询表达式
查询表达式使用类似于 SQL 或 XQuery 的声明性语法来查询 IEnumerable 集合。在编译时,查询语法转换为对 LINQ 提供程序的标准查询运算符扩展方法实现的方法调用。应用程序通过使用 using 指令指定适当的命名空间来控制范围内的标准查询运算符。下面的查询表达式获取一个字符串数组,按字符串中的第一个字符对字符串进行分组,然后对各组进行排序。
var query = from str in stringArray
group str by str[0] into stringGroup
orderby stringGroup.Key
select stringGroup;
|
-
- 隐式类型化变量
不必在声明并初始化变量时显式指定类型,您可以使用 var 修饰符来指示编译器推断并分配类型,声明为 var 的变量与显式指定其类型的变量一样都是强类型。通过使用 var,可以创建匿名类型,但它可用于任何局部变量。也可以使用隐式类型声明数组。
var number = 5;
var name = "Virginia";
var query = from str in stringArray
where str[0] == 'm'
select str;
|
-
- 对象和集合初始值设定项
通过对象和集合初始值设定项,初始化对象时无需为对象显式调用构造函数。初始值设定项通常用在将源数据投影到新数据类型的查询表达式中。假定一个类名为 Customer,具有公共 Name 和 Phone 属性,可以按下列代码中所示使用对象初始值设定项:
Customer cust = new Customer { Name = "Mike", Phone = "555-1212" };
|
-
- 匿名类型
匿名类型由编译器构建,且类型名称只可用于编译器。匿名类型提供了一种在查询结果中临时分组一组属性的方便方法,无需定义单独的命名类型。使用新的表达式和对象初始值设定项初始化匿名类型。
select new {name = cust.Name, phone = cust.Phone};
|
-
- 扩展方法
扩展方法是一种可与类型关联的静态方法,因此可以像实例方法那样对类型调用它。实际上,此功能使您能够将新方法“添加”到现有类型,而不会实际修改它们。标准查询运算符是一组扩展方法,它们为实现 IEnumerable<T> 的任何类型提供 LINQ 查询功能。
-
- Lambda 表达式
Lambda 表达式是一种内联函数,该函数使用 => 运算符将输入参数与函数体分离,并且可以在编译时转换为委托或表达式树。在 LINQ 编程中,在您对标准查询运算符进行直接方法调用时,会遇到 lambda 表达式。
-
- 自动实现的属性
通过自动实现的属性,可以更简明地声明属性。当您如下面的示例中所示声明属性时,编译器将创建一个私有的匿名支持字段,该字段只能通过属性 getter 和 setter 进行访问。
public string Name {get; set;}
|
- LINQ 泛型
-
- IEnumerable<T> 变量
IEnumerable<Customer> customerQuery =
from cust in customers
where cust.City == "London"
select cust;
foreach (Customer customer in customerQuery)
{
Console.WriteLine(customer.LastName + ", " + customer.FirstName);
}
|
-
- 编译器处理泛型类型声明
如果您愿意,可以使用 var 关键字来避免使用泛型语法。 var 关键字指示编译器通过查看在 from 子句中指定的数据源来推断查询变量的类型。当变量的类型明显或显式指定嵌套泛型类型(如由组查询生成的那些类型)并不重要时,var 关键字很有用。通常,我们建议如果您使用 var,应意识到这可能使您的代码更难以让别人理解。
var customerQuery2 =
from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine(customer.LastName + ", " + customer.FirstName);
}
|
- LINQ to Objects
术语“LINQ to Objects”是指直接对任意 IEnumerable 或 IEnumerable<T> 集合使用 LINQ 查询,无需使用中间 LINQ 提供程序或 API,如 LINQ to SQL 或 LINQ to XML。 可以使用 LINQ 来查询任何可枚举的集合,如 List<T>、Array 或 Dictionary<TKey, TValue>。 该集合可以是用户定义的集合,也可以是 .NET Framework API 返回的集合。
从根本上说,LINQ to Objects 表示一种新的处理集合的方法。 采用旧方法,您必须编写指定如何从集合检索数据的复杂的 foreach 循环。 而采用 LINQ 方法,您只需编写描述要检索的内容的声明性代码。
另外,与传统的 foreach 循环相比,LINQ 查询具有三大优势:
-
- 它们更简明、更易读,尤其在筛选多个条件时。
- 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能。
- 无需修改或只需做很小的修改即可将它们移植到其他数据源。