語言集成查詢(Language-Integrated Query),簡稱LINQ,.NET中的LINQ體系如下圖所示:
在編程語言層次,LINQ對于不同的數(shù)據(jù)源提供了相同的查詢語法,方便了程序員操作不同的數(shù)據(jù)源。
可查詢類型
LINQ之所以能夠使用相同的語法操作不同的數(shù)據(jù)源,是因為和LINQ直接打交道的是可查詢類型而非數(shù)據(jù)源,在LINQ中,直接或間接實現(xiàn)了IEnumerable<T>接口的類型稱為可查詢類型, .NET中如:List<T>,Dictionary<TKey,TValue>,數(shù)組(由CLR負責隱式實現(xiàn)IEnumerable<T>接口)等,實現(xiàn)了IEnumerable<T>接口。
IQueryable<out T>繼承自IEnumerable<T>,是個標記接口。
可查詢類型無需額外操作即可進行LINQ操作,若數(shù)據(jù)源在內(nèi)存中不以可查詢類型的形式存在,那么LINQ提供程序必須要先將數(shù)據(jù)源轉(zhuǎn)換為可查詢類型,如LINQ to XML將XML文件轉(zhuǎn)換為可查詢的XElement類型:
XElement contacts = XElement.Load(@"c:\myContactList.xml");
LINQ 提供程序
LINQ提供程序(LINQ Provider)提供了對特定的數(shù)據(jù)源進行標準的LINQ操作及一些擴展操作(如:LINQ to XML),不同的LINQ提供程序?qū)τ谝恍┫嗤Q的擴展方法會提供不同的實現(xiàn)方式。.NET中預定義的LINQ提供程序包括:LINQ to Object、LINQ to XML (C#)、LINQ to SQL、LINQ to DataSet、LINQ to Entities。
LINQ to SQL不建議使用,用LINQ to Entities來替代。
LINQ查詢包含三個步驟:
- 獲取數(shù)據(jù)源
- 創(chuàng)建查詢語句
- 執(zhí)行查詢
LINQ查詢方式
LINQ 表達式(又稱為查詢表達式)
以from關(guān)鍵字開頭,select關(guān)鍵字結(jié)尾。擴展方法(又稱為標準查詢)
System.Linq.Enumerable類和System.Linq.Queryable類,分別針對IEnumerable<T>和IQueryable<T>接口進行的擴展。.NET也提供了幾個對IEnumerable和IQueryable接口進行操作的擴展方法,如: Cast<TResult>和OfType<TResult>。LINQ 表達式和擴展方法混合使用
(from e in Employees
where e.Salary>8000
select e).ToList()
LINQ表達式和擴展方法對比:
- 對于排序、分組、聯(lián)合查詢使用LINQ表達式更為方便
//以排序為例,使用年齡、姓名、郵箱進行排序,
//LINQ表達式中使用逗號分隔排序字段,而擴展方法則需要多次調(diào)用相應的擴展方法
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);
- 擴展方法能夠提供比LINQ表達式更復雜的查詢
//取第26行到36行范圍內(nèi)的數(shù)據(jù)
var result=Employees.Skip(25).Take(10);
//使用LINQ表達式我表示寫不出來......
LINQ表達式是對常用擴展方法在語法層面上的簡化,LINQ表達式有著更好的可讀性,在編譯時LINQ表達式會被轉(zhuǎn)化為對擴展方法的調(diào)用。
LINQ查詢特點:
-
延遲查詢
若查詢表達式的返回結(jié)果是IEnumerable<T>類型,則在聲明查詢表達式時不會執(zhí)行查詢,而是在迭代查詢變量時才進行查詢。
MSDN上的經(jīng)典LINQ查詢流程圖(延遲查詢) 立即查詢
若查詢表達式返回單個值或者使用了ToList<T>、ToArray<T>等方法時會執(zhí)行立即查詢,因為這些操作會遍歷數(shù)據(jù)。
一句話總結(jié),若查詢表達式不包含對數(shù)據(jù)源的遍歷操作則執(zhí)行延遲查詢,否則會進行立即查詢。
LINQ表達式中的查詢關(guān)鍵字
表格中的英文沒什么難點,就不翻譯了 :)
| 關(guān)鍵字 | 描述 |
|---|---|
| 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中,一個查詢表達式被編譯為表達式樹或者委托,查詢結(jié)果為IEnumerable<T>類型則被編譯為委托,查詢結(jié)果是IQueryable或IQueryable<T>類型則被編譯為表達式樹,在運行時表達式樹會被解析為適合于數(shù)據(jù)源的查詢語句。
- System.Collection.Generic.IEnumerable<T>
IEnumerable先將數(shù)據(jù)放到本地內(nèi)存中,然后再執(zhí)行過濾操作(如果有的話),適合于對當前進程中的數(shù)據(jù)進行查詢操作,如:LINQ to XML、LINQ to Object。
- System.Linq.IQueryable<T>
在執(zhí)行查詢操作時,IQueryable先在服務器端進行過濾操作(如果有的話),然后再將數(shù)據(jù)放到本地內(nèi)存中。
IQueryable適合使用對進程外(如數(shù)據(jù)庫)的數(shù)據(jù)進行查詢操作,如:LINQ to Entities。
兩個命名空間
System.Linq
System.Linq命名空間中包含用于LINQ查詢的類和接口
System.Linq.Expressions
System.Linq.Expressions 命名空間包含了用于創(chuàng)建表達式樹的類、 接口。
LINQ的優(yōu)缺點
優(yōu)點
- 對不同的數(shù)據(jù)源提供了幾乎一致的查詢操作,這可使我們更多的去關(guān)注業(yè)務邏輯而非對數(shù)據(jù)源的操作
- 提供編譯期的類型檢查
- 在書寫LINQ查詢表達式時可以使用Visual Studio的智能提示
- 調(diào)試方便
缺點
- 對于復雜的查詢操作顯得力不從心
- 容易寫出性能不高的查詢表達式
結(jié)語
本篇是自己學習LINQ的總結(jié),不求面面俱到。通篇以文字敘述為主,輔以少量代碼,若有錯誤希望大家指出。
工具推薦
LINQ Pad是一款輕量級的數(shù)據(jù)查詢工具,在LINQ Pad中可以使用LINQ表達式、擴展方法、SQL語句等對數(shù)據(jù)庫進行操作,簡單易用功能強大。

書目推薦:
《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
