.NET中數據訪問方式之LINQ
語言集成查詢(Language-Integrated Query),簡稱LINQ,.NET中的LINQ體系如下圖所示:
LINQ Hierarchy
在編程語言層次,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提供程序提供了對特定的數據源進行標準的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
來替代。
LINQ查詢包含三個步驟:
獲取數據源
創建查詢語句
執行查詢
LINQ查詢方式
LINQ 表達式
以
from
關鍵字開頭,select
關鍵字結尾。擴展方法
System.Linq.Enumerable
類和System.Linq.Queryable
類,分別針對IEnumerable<T>
和IQueryable<T>
接口進行的擴展。LINQ 表達式和擴展方法混合使用
(from e in Employeeswhere e.Salary>8000
select e).ToList()
LINQ表達式和擴展方法對比:
LINQ表達式和擴展方法在編譯後的代碼沒有什麼區別
對於排序、分組、聯合查詢使用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);
擴展方法能夠提供比LINQ表達式更復雜的查詢
//取第26行到36行範圍內的數據
var result=Employees.Skip(25).Take(10);
//使用LINQ表達式我表示寫不出來......
LINQ查詢特點:
延遲查詢
在聲明查詢表達式時不會執行查詢,而是在迭代查詢變量時才進行查詢。
MSDN上的經典LINQ查詢流程圖(延遲查詢)
立即查詢
若查詢表達式返回單個值或者使用了
ToList<T>
、ToArray<T>
、Count()
等方法也會執行立即查詢。
LINQ表達式中的查詢關鍵字
表格中的英文沒什麼難點,就不翻譯了 :)
關鍵字 | 描述 |
---|---|
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 ajoinclause. |
on | Contextual keyword in ajoinclause. |
equals | Contextual keyword in ajoinclause. |
by | Contextual keyword in agroupclause. |
ascending | Contextual keyword in anorderbyclause. |
descending | Contextual keyword in anorderbyclause. |
兩個接口
在LINQ中,一個查詢表達式被編譯為表達式樹或者委託,查詢結果為IEnumerable<T>
類型則被編譯為委託,查詢結果是IQueryable
或IQueryable<T>
類型則被編譯為表達式樹,在運行時表達式樹會被解析為適合於數據源的查詢語句。
System.Collection.IEnumerable
IEnumerable
先將數據放到內存中,然後在執行過濾操作(如果有的話),適合於對內存中的數據進行查詢操作,如:LINQ to XML
、LINQ to Object
。
System.Linq.IQueryable
在執行查詢操作時,
IQueryable
先在服務器端進行過濾操作(如果有的話),然後再將數據放到內存中。IQueryable
適合使用對內存外(如數據庫)的數據進行查詢操作,如:LINQ to Entities
。
兩個命名空間
System.Linq
System.Linq命名空間中包含用於LINQ查詢的類和接口
System.Linq.Expressions
System.Linq.Expressions 命名空間包含了用於創建表達式樹的類、 接口。
LINQ的優缺點
優點
對不同的數據源提供了幾乎一致的查詢操作,這可使我們更多的去關注業務邏輯而非對數據源的操作
提供編譯期的類型檢查
在書寫LINQ查詢表達式時可以使用Visual Studio的智能提示
調試方便
缺點
對於複雜的查詢操作顯得力不從心
容易寫出性能不高的查詢表達式
結語
本篇是自己學習LINQ的總結,不求面面俱到。通篇以文字敘述為主,輔以少量代碼,若有錯誤希望大家指出。
工具推薦
LINQ Pad是一款輕量級的數據查詢工具,在LINQ Pad中可以使用LINQ表達式、擴展方法、SQL語句等對數據庫進行操作,簡單易用功能強大。