1、如何使用LINQ
LINQ作為一種數據查詢編碼方式,本身並不是獨立的開發語句,也不能進行應用程序開發。在.NET3.5中,可以在C#中集成LINQ查詢代碼。在任何源代碼文件中,要使用LINQ查詢功能,必須引用System.Linq命名空間。使用LINQ to XML要引用System.Xml.Linq命名空間,使用LINQ to ADO.NET要引用System.Data.Linq命名空間。
2、LINQ查詢表達式
查詢表達式關鍵字:
from:指定要查找的數據源以及范圍變量,多個from子句則表示從多個數據源中查找數據
select: 指定查詢要返回的目標數據,可以指定任何類型,甚至是匿名類型
where: 指定元素的篩選條件,多個where子句則表示了並列關系,必須全部都滿足才能入選
orderby: 指定元素的排序字段和排序方式,當有多個排序字段時,有字段順序確定主次關系,可以指定升序和降序兩種排序方式
group: 指定元素的分組字段
join: 指定多個數據源的關聯方式
2.1 用from子句指定數據源
每個LINQ查詢語句都是以from子句開始,from子句包括以下兩個功能:
●指定查詢將采用的數據源
●定義一個本地變量,表示數據源中的單個元素
如: from localval in datasource
一般情況下,不用為from子句的localval元素指定數據類型,編譯器會根據數據源類型為它分配合適的類型,通常為IEnumerable<T>中的類型T。例如,下面的val會被分配為int類型
int[] arr = {1,2,3,4,5};
var query =
from val in arr
select val;
特殊情況下,開發人員需要為本地變量指定數據類型,比如上面的例子中,如果希望將arr中的元素作為object類型進行處理,而不是int類型,需要指定val2為object類型,因為arr中元素是int類型,數據object類型的子類型,所以可以直接轉換,如下:
int[] arr = {1,2,3,4,5};
var query =
from object val2 in arr
select val2;
值得注意的是,編譯器並不會檢查本地變量的具體類型,所以即使指定類型不正確,編譯器也不會報錯,但是在下面使用該查詢時,會在運行時進行類型檢查,從而產生異常。
2.2 用select子句指定目標數據
LINQ查詢表達式必須以select或者group子句結束。select子句中要選擇的目標數據不僅可以是數據源中的元素,還可以是該元素的不同操作結果,包括屬性、方法、運算,如下面兩個例子:
var query2 = from val in arr select val.Name; foreach(string item in query2) { Console.Write("{0}, ",item); } Console.WriteLine(); var query3 = from val in arr select val.Name.Length; foreach (int item in query3) { Console.Write("{0}, ", item); }
在某些特殊的場合,往往查詢結果只是臨時使用一下,而且查詢結果的數據包括很多字段,並非簡單的一個屬性、方法返回值等。在LINQ中,可以在select子句中使用匿名類型來解決這個問題。如query4中的select子句通過匿名類型定義返回結果,因為編碼無法使用匿名類型,所以在foreach只能通過var(可變類型)關鍵字讓編譯器自動判斷查詢中元素類型。
var query4 = from val in arr select new { val.Name, val.Age, NameLen = val.Name.Length}; foreach(var item2 in query4) { Console.WriteLine(item2); }
2.3 用where子句指定篩選條件
作用:指定查詢的過濾條件
格式:where Expression
int[] ary = {1,2,3,4,5,6,7,8,9,10,11,12};
var query =
from val in ary
where (val > 5) && (val < 10)
select val;
2.4 用orderby子句進行排序
作用:對查詢結果進行排序
格式: orderby element [sortType]
其中,sortType是可選參數,表示排序類型,包括升序(ascending)和降序(descending)兩個參數,默認為升序。
int[] ary = { 9,54,32,1,67,43,0,9,7,4,9,2,23,66,61}; var query5 = from val in ary orderby val select val; foreach(var item in query5) { Console.Write("{0} ",item); } Console.WriteLine(); Console.WriteLine(); var query6 = from val in ary orderby val descending select val; foreach (var item in query6) { Console.Write("{0} ", item); }
結果是:
在LINQ中,orderby可以同時指定多個排序元素,也可以為每個排序元素指定獨立的排序方式。orderby後的第一個排序元素為主要排序,第二個為次要排序,依次類推。如下面例子,先按照姓名字符數量進行升序排列,再按照年齡降序排列。
var query7 = from val in arr orderby val.Name.Length ascending, val.Age descending select val; foreach(var item in query7) { Console.WriteLine(item); }
結果:
2.5 用group子句進行分組
作用:對數據進行分組
格式:group element by key
var query8 = from val in arr group val by val.Xingbie; foreach(var grp in query8) { Console.WriteLine(grp.Key); foreach(var st in grp) { Console.WriteLine("\t{0}",st); } }
有時候需要對分組結果進行排序、在查詢等操作,這時候就需要使用into 關鍵字將group查詢結果存在一個臨時變量中,並且必須使用新的select或者group子句對其進行查詢,也可使用orderby進行排序,where進行過濾等等,into的語句格式如下
group element by key into tmpgrp
其中,tmpgrp就是臨時變量,用來臨時保存group產生的結果,提供後面的查詢操作。
var query9 = from val in arr group val by val.Age into stgrp orderby stgrp.Key descending select stgrp; foreach(var st in query9) { Console.WriteLine("{0}歲的學生:",st.Key); foreach(var stu in st) { Console.WriteLine("\t{0}",stu); } }
2.6 用join子句進行關聯
join子句實現聯接操作,將來自不同源序列,並且在對象模型中沒有直接關系的元素相關聯,唯一的要求就是每個源中的元素需要共享某個可以進行比較,以判斷是否相等的值。
join子句可以實現3種類型的聯接: 內部聯接、分組聯接、左外部聯接。
2.6.1 用join子句進行內部聯接
格式: join element in datasource on exp1 equals exp2
datasource 表示數據源,它是聯接要使用的第二個數據集,element 表示存儲datasource中元素的本地變量,exp1 和 exp2 表示兩個表達式,它們具有相同的數據類型,可以用equals進行比較,如果exp1 和 exp2 相等,則當前元素將添加到查詢結果中。
int[] intarray1 = { 5,15,25,30,33,40}; int[] intarray2 = { 10,20,30,40,50,60,70,80,90,100}; var query12 = from val1 in intarray1 join val2 in intarray2 on val1 % 5 equals val2 % 15 select new { VAL1 = val1,VAL2 = val2}; foreach(var val in query12) { Console.WriteLine(val); }
2.6.2 用join子句進行分組聯接
格式:join element in datasource on exp1 equals exp2 into grpname
into 關鍵字表示將這些數據分組並保存到grpname中,grpname是保存一組數據的集合。
分組聯接產生分層的數據結果,它將第一個集合中的每一個元素與第二個集合中的一組相關元素進行配對。值得注意的是,即使第一個集合中的元素在第二個集合中沒有配對的元素,也會為它產生一個空的分組對象。
var query13 = from val1 in intarray1 join val2 in intarray2 on val1 % 5 equals val2 % 15 into grpName select new { VAL1 = val1, VAL2 = grpName}; foreach(var val in query13) { Console.Write("{0}: ",val.VAL1); foreach(var obj in val.VAL2) { Console.Write("{0} ",obj); } Console.WriteLine(); }
請比較query12 和 query13 的運行結果的區別。
2.6.3 用join子句進行左外部聯接
左外部聯接返回第一個集合元素的所有元素,無論它是否在第二個集合中有相關元素。在LINQ中,通過對分組聯接的結果調用DefaultEmpty()來執行左外部聯接。
var query14 = from val1 in intarray1 join val2 in intarray2 on val1 % 5 equals val2 % 15 into grpName from grp in grpName.DefaultIfEmpty() select new { VAL1 = val1 , VAL2 = grp}; foreach(var val in query14) { Console.WriteLine(val); }
2.7 使用let子句擴展范圍變量
用於創建查詢自身的范圍變量
string[] strings ={ "I am a new Student.", "You are a talent" }; var query = from sentences in strings let words = sentences.Split(' ') from word in words let w = word.ToLower() where w[0] == 'a' || w[0] == 'e' || w[0] == 'i' || w[0] == 'o' || w[0] == 'u' select word; foreach (var word in query) { Console.Write(word + ","); }
需求:將字符串數組中的兩句英文語句中所有的元音字母打頭的單詞輸出到控制台
分析:首先遍歷字符串數組中的每個字符串,用let子句創建查詢自身的范圍變量words,並調用Split(' ')方法,將每個字符串中以空格分割為單詞存入words變量中,然後再次使用let子句創建查詢自身的范圍變量word,並調用ToLower()方法,將每個單詞都變為小寫,最後篩選出首字母為元音的單詞進行返回。
PS:本文完整代碼來自:http://www.cnblogs.com/crandy/p/4546126.html