语言集成查询(Language-Integrated Query),简称LINQ,.NET中的LINQ体系如下图所示:
在编程语言层次,LINQ对于不同的数据源提供了相同的查询语法,方便了程序员操作不同的数据源。
LINQ之所以能够使用相同的语法操作不同的数据源,是因为和LINQ直接打交道的是可查询类型而非数据源,在LINQ中,直接或间接实现了IEnumerable<T>
接口的类型称为可查询类型, .NET中如:List<T>
,Dictionary<TKey,TValue>
,数组(由CLR负责隐式实现IEnumerable<T>接口)等,实现了IEnumerable<T>接口。
IQueryable<out T>继承自IEnumerable<T>,是个标记接口。
可查询类型无需额外操作即可进行LINQ操作,若数据源在内存中不以可查询类型的形式存在,那么LINQ提供程序必须要先将数据源转换为可查询类型,如LINQ to XML
将XML文件转换为可查询的XElement
类型:
XElement contacts = XElement.Load(@"c:\myContactList.xml");
LINQ提供程序(LINQ Provider)提供了对特定的数据源进行标准的LINQ操作及一些扩展操作(如:LINQ to XML),不同的LINQ提供程序对于一些相同名称的扩展方法会提供不同的实现方式。.NET中预定义的LINQ提供程序包括:LINQ to Object、LINQ to XML (C#)、LINQ to SQL、LINQ to DataSet、LINQ to Entities。
LINQ to SQL
不建议使用,用LINQ to Entities
来替代。
from
关键字开头,select
关键字结尾。
System.Linq.Enumerable
类和System.Linq.Queryable
类,分别针对IEnumerable<T>
和IQueryable<T>
接口进行的扩展。.NET也提供了几个对IEnumerable和IQueryable接口进行操作的扩展方法,如: Cast<TResult>和OfType<TResult>。
(from e in Employees
where e.Salary>8000
select e).ToList()
LINQ表达式和扩展方法在编译后的代码没有什么区别
//以排序为例,使用年龄、姓名、邮箱进行排序,
//LINQ表达式中使用逗号分隔排序字段,而扩展方法则需要多次调用相应的扩展方法
var result= from e in Employees
where e.Age>50 && e.Salary>8000
orderby e.Age,e.Name,e.Email
select e;
//等价的扩展方法
var result=Employees
.Where(e=>e.Age>50 && e.Salary>8000)
.OrderBy(e=>e.Age)
.ThenBy(e=>e.Name)
.ThenBy(e=>e.Email);
//取第26行到36行范围内的数据
var result=Employees.Skip(25).Take(10);
//使用LINQ表达式我表示写不出来......
LINQ表达式是对常用扩展方法在语法层面上的简化,LINQ表达式有着更好的可读性,在编译时LINQ表达式会被转化为对扩展方法的调用。
IEnumerable<T>
类型,则在声明查询表达式时不会执行查询,而是在迭代查询变量时才进行查询。贴一幅MSDN上的经典LINQ查询流程图(延迟查询):
ToList<T>
、ToArray<T>
等方法时会执行立即查询,因为这些操作会遍历数据。
一句话总结,若查询表达式不包含对数据源的遍历操作则执行延迟查询,否则会进行立即查询。
表格中的英文没什么难点,就不翻译了 :)
关键字 | 描述 |
---|---|
from | Specifies a data source and a range variable (similar to an iteration variable). |
where | Filters source elements based on one or more Boolean expressions separated by logical AND and OR operators. |
select | Specifies the type and shape that the elements in the returned sequence will have when the query is executed. |
group | Groups query results according to a specified key value. |
into | Provides an identifier that can serve as a reference to the results of a join, group or select clause. |
orderby | Sorts query results in ascending or descending order based on the default comparer for the element type. |
join | Joins two data sources based on an equality comparison between two specified matching criteria. |
let | Introduces a range variable to store sub-expression results in a query expression. |
in | Contextual keyword in a join clause. |
on | Contextual keyword in a join clause. |
equals | Contextual keyword in a join clause. |
by | Contextual keyword in a group clause. |
ascending | Contextual keyword in an orderby clause. |
descending | Contextual keyword in an orderby clause. |
在LINQ中,一个查询表达式被编译为表达式树或者委托,查询结果为IEnumerable<T>
类型则被编译为委托,查询结果是IQueryable
或IQueryable<T>
类型则被编译为表达式树,在运行时表达式树会被解析为适合于数据源的查询语句。
IEnumerable
先将数据放到本地内存中,然后再执行过滤操作(如果有的话),适合于对当前进程中的数据进行查询操作,如:LINQ to XML
、LINQ to Object
。IQueryable
先在服务器端进行过滤操作(如果有的话),然后再将数据放到本地内存中。
IQueryable
适合使用对进程外(如数据库)的数据进行查询操作,如:LINQ to Entities
。System.Linq命名空间中包含用于LINQ查询的类和接口
System.Linq.Expressions 命名空间包含了用于创建表达式树的类、 接口。
本篇是自己学习LINQ的总结,不求面面俱到。通篇以文字叙述为主,辅以少量代码,若有错误希望大家指出。
LINQ Pad是一款轻量级的数据查询工具,在LINQ Pad中可以使用LINQ表达式、扩展方法、SQL语句等对数据库进行操作,简单易用功能强大。
《LINQ Interview Questions Answers》
Introduction to LINQ Queries (C#) Standard Query Operators Overview (C#) Query Expression Syntax for Standard Query Operators (C#) Data Transformations with LINQ (C#) LINQ provider basics Enabling a Data Source for LINQ Querying LINQ: Building an IQueryable Provider – Part I
本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接。
如有问题, 请发送邮件和作者联系。