ASP.NET開(kāi)發(fā)大全第21章.使用LINQ查詢(xún)_第1頁(yè)
ASP.NET開(kāi)發(fā)大全第21章.使用LINQ查詢(xún)_第2頁(yè)
ASP.NET開(kāi)發(fā)大全第21章.使用LINQ查詢(xún)_第3頁(yè)
ASP.NET開(kāi)發(fā)大全第21章.使用LINQ查詢(xún)_第4頁(yè)
ASP.NET開(kāi)發(fā)大全第21章.使用LINQ查詢(xún)_第5頁(yè)
已閱讀5頁(yè),還剩28頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

·PAGE218·PAGEPAGE510第21章使用LINQ查詢(xún)了解了基本的LINQ基本概念,以及Lambda表達(dá)式基礎(chǔ)后,就能夠使用LINQ進(jìn)行應(yīng)用程序開(kāi)發(fā)。LINQ使用了Lambda表達(dá)式,以及底層接口實(shí)現(xiàn)了對(duì)集合的訪(fǎng)問(wèn)和查詢(xún),開(kāi)發(fā)人員能夠使用LINQ對(duì)不同的對(duì)象,包括數(shù)據(jù)庫(kù)、數(shù)據(jù)集和XML文檔進(jìn)行查詢(xún)。21.1LINQ查詢(xún)概述LINQ可以對(duì)多種數(shù)據(jù)源和對(duì)象進(jìn)行查詢(xún),如數(shù)據(jù)庫(kù)、數(shù)據(jù)集、XML文檔甚至是數(shù)組,這在傳統(tǒng)的查詢(xún)語(yǔ)句中是很難實(shí)現(xiàn)的。如果有一個(gè)集合類(lèi)型的值需要進(jìn)行查詢(xún),則必須使用Where等方法進(jìn)行遍歷,而使用LINQ可以仿真SQL語(yǔ)句的形式進(jìn)行查詢(xún),極大的降低了難度。21.1.1準(zhǔn)備數(shù)據(jù)源既然LINQ可以查詢(xún)多種數(shù)據(jù)源和對(duì)象,這些對(duì)象可能是數(shù)組,可能是數(shù)據(jù)集,也可能是數(shù)據(jù)庫(kù),那么在使用LINQ進(jìn)行數(shù)據(jù)查詢(xún)時(shí)首先需要準(zhǔn)備數(shù)據(jù)源。1.?dāng)?shù)組數(shù)組中的數(shù)據(jù)可以被LINQ查詢(xún)語(yǔ)句查詢(xún),這樣就省去了復(fù)雜的數(shù)組遍歷。數(shù)組數(shù)據(jù)源示例代碼如下所示。string[]str={"學(xué)習(xí)","學(xué)習(xí)LINQ","好好學(xué)習(xí)","生活很美好"};int[]inter={1,2,3,4,5,6,7,8,9};數(shù)組可以看成是一個(gè)集合,雖然數(shù)組沒(méi)有集合的一些特性,但是從另一個(gè)角度上來(lái)說(shuō)可以看成是一個(gè)集合。在傳統(tǒng)的開(kāi)發(fā)過(guò)程中,如果要篩選其中包含“學(xué)習(xí)”字段的某個(gè)字符串,則需要遍歷整個(gè)數(shù)組。2.SQLServer在數(shù)據(jù)庫(kù)操作中,同樣可以使用LINQ進(jìn)行數(shù)據(jù)庫(kù)查詢(xún)。LINQ以其優(yōu)雅的語(yǔ)法和面向?qū)ο蟮乃枷肽軌蚍奖愕倪M(jìn)行數(shù)據(jù)庫(kù)操作,為了使用LINQ進(jìn)行SQLServer數(shù)據(jù)庫(kù)查詢(xún),可以創(chuàng)建兩個(gè)表,這兩個(gè)表的結(jié)構(gòu)如下所示。Student(學(xué)生表):S_ID:學(xué)生ID。S_NAME:學(xué)生姓名。S_CLASS:學(xué)生班級(jí)。C_ID:所在班級(jí)的ID。上述結(jié)構(gòu)描述了一個(gè)學(xué)生表,可以使用SQL語(yǔ)句創(chuàng)建學(xué)生表,示例代碼如下所示。USE[student]GOSETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGOCREATETABLE[dbo].[Student]( [S_ID][int]IDENTITY(1,1)NOTNULL, [S_NAME][nvarchar](50)COLLATEChinese_PRC_CI_ASNULL, [S_CLASS][nvarchar](50)COLLATEChinese_PRC_CI_ASNULL, [C_ID][int]NULL,CONSTRAINT[PK_Student]PRIMARYKEYCLUSTERED( [S_ID]ASC)WITH(PAD_INDEX=OFF,STATISTICS_NORECOMPUTE=OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)ON[PRIMARY])ON[PRIMARY]為了更加詳細(xì)的描述一個(gè)學(xué)生所有的基本信息,就需要?jiǎng)?chuàng)建另一個(gè)表對(duì)該學(xué)生所在的班級(jí)進(jìn)行描述,班級(jí)表結(jié)構(gòu)如下所示。Class(班級(jí)表):C_ID:班級(jí)ID。C_GREAD:班級(jí)所在的年級(jí)。C_INFOR:班級(jí)專(zhuān)業(yè)。上述代碼描述了一個(gè)班級(jí)的基本信息,同樣可以使用SQL語(yǔ)句創(chuàng)建班級(jí)表,示例代碼如下所示。USE[student]GOSETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGOCREATETABLE[dbo].[Class]( [C_ID][int]IDENTITY(1,1)NOTNULL, [C_GREAD][nvarchar](50)COLLATEChinese_PRC_CI_ASNULL, [C_INFOR][nvarchar](50)COLLATEChinese_PRC_CI_ASNULL,CONSTRAINT[PK_Class]PRIMARYKEYCLUSTERED( [C_ID]ASC)WITH(PAD_INDEX=OFF,STATISTICS_NORECOMPUTE=OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)ON[PRIMARY])ON[PRIMARY]上述代碼在Student數(shù)據(jù)庫(kù)中創(chuàng)建了一個(gè)班級(jí)表,開(kāi)發(fā)人員能夠向數(shù)據(jù)庫(kù)中添加相應(yīng)的信息以準(zhǔn)備數(shù)據(jù)源。3.?dāng)?shù)據(jù)集LINQ能夠通過(guò)查詢(xún)數(shù)據(jù)集進(jìn)行數(shù)據(jù)的訪(fǎng)問(wèn)和整合;通過(guò)訪(fǎng)問(wèn)數(shù)據(jù)集,LINQ能夠返回一個(gè)集合變量;通過(guò)遍歷集合變量可以進(jìn)行其中數(shù)據(jù)的訪(fǎng)問(wèn)和篩選。在第9章中講到了數(shù)據(jù)集的概念,開(kāi)發(fā)人員能夠?qū)?shù)據(jù)庫(kù)中的內(nèi)容填充到數(shù)據(jù)集中,也可以自行創(chuàng)建數(shù)據(jù)集。數(shù)據(jù)集是一個(gè)存在于內(nèi)存的對(duì)象,該對(duì)象能夠模擬數(shù)據(jù)庫(kù)的一些基本功能,可以模擬小型的數(shù)據(jù)庫(kù)系統(tǒng),開(kāi)發(fā)人員能夠使用數(shù)據(jù)集對(duì)象在內(nèi)存中創(chuàng)建表,以及模擬表與表之間的關(guān)系。在數(shù)據(jù)集的數(shù)據(jù)檢索過(guò)程中,往往需要大量的if、else等判斷才能檢索相應(yīng)的數(shù)據(jù)。使用LINQ進(jìn)行數(shù)據(jù)集中數(shù)據(jù)的整理和檢索可以減少代碼量并優(yōu)化檢索操作。數(shù)據(jù)集可以是開(kāi)發(fā)人員自己創(chuàng)建的數(shù)據(jù)集也可以是現(xiàn)有數(shù)據(jù)庫(kù)填充的數(shù)據(jù)集,這里使用上述SQLServer創(chuàng)建的數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行數(shù)據(jù)集的填充。21.1.2使用LINQ在傳統(tǒng)對(duì)象查詢(xún)中,往往需要很多的if、else語(yǔ)句進(jìn)行數(shù)組或?qū)ο蟮谋闅v,例如在數(shù)組中尋找相應(yīng)的字段,實(shí)現(xiàn)起來(lái)往往比較復(fù)雜,而使用LINQ就簡(jiǎn)化了對(duì)象的查詢(xún)。由于前面已經(jīng)準(zhǔn)備好了數(shù)據(jù)源,那么就能夠分別使用LINQ語(yǔ)句進(jìn)行數(shù)據(jù)源查詢(xún)。1.?dāng)?shù)組在前面的章節(jié)中,已經(jīng)創(chuàng)建了一個(gè)數(shù)組作為數(shù)據(jù)源,數(shù)組示例代碼如下所示。int[]inter={1,2,3,4,5,6,7,8,9};上述代碼是一個(gè)數(shù)組數(shù)據(jù)源,如果開(kāi)發(fā)人員需要從其中的元素中搜索大于5的數(shù)字,傳統(tǒng)的方法應(yīng)該遍歷整個(gè)數(shù)組并判斷該數(shù)字是否大于5,如果大于5則輸出,否則不輸出,示例代碼如下所示。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq; //使用必要的命名空間usingSystem.Text;namespace_21_1{classProgram{staticvoidMain(string[]args){string[]str={"學(xué)習(xí)","學(xué)習(xí)LINQ","好好學(xué)習(xí)","生活很美好"}; //定義數(shù)組int[]inter={1,2,3,4,5,6,7,8,9};for(inti=0;i<inter.Length;i++) //遍歷數(shù)組{if(inter[i]>5) //判斷數(shù)組元素的值是否大于5{Console.WriteLine(inter[i].ToString()); //輸出對(duì)象}}Console.ReadKey();}}}上述代碼非常簡(jiǎn)單,將數(shù)組從頭開(kāi)始遍歷,遍歷中將數(shù)組中的的值與5相比較,如果大于5就會(huì)輸出該值,如果小于5就不會(huì)輸出該值。雖然上述代碼實(shí)現(xiàn)了功能的要求,但是這樣編寫(xiě)的代碼繁冗復(fù)雜,也不具有擴(kuò)展性。如果使用LINQ查詢(xún)語(yǔ)句進(jìn)行查詢(xún)就非常簡(jiǎn)單,示例代碼如下所示。classProgram{staticvoidMain(string[]args){string[]str={"學(xué)習(xí)","學(xué)習(xí)LINQ","好好學(xué)習(xí)","生活很美好"}; //定義數(shù)組int[]inter={1,2,3,4,5,6,7,8,9}; //定義數(shù)組varst=fromsininterwheres>5selects; //執(zhí)行LINQ查詢(xún)語(yǔ)句foreach(vartinst) //遍歷集合元素{Console.WriteLine(t.ToString()); //輸出數(shù)組}Console.ReadKey();}}使用LINQ進(jìn)行查詢(xún)之后會(huì)返回一個(gè)IEnumerable的集合。在上一章講過(guò),IEnumerable是.NET框架中最基本的集合訪(fǎng)問(wèn)器,可以使用foreach語(yǔ)句遍歷集合元素。使用LINQ查詢(xún)數(shù)組更加容易被閱讀,LINQ查詢(xún)語(yǔ)句的結(jié)構(gòu)和SQL語(yǔ)法十分類(lèi)似,LINQ不僅能夠查詢(xún)數(shù)組,還可以通過(guò).NET提供的編程語(yǔ)言進(jìn)行篩選。例如str數(shù)組變量,如果要查詢(xún)其中包含“學(xué)習(xí)”的字符串,對(duì)于傳統(tǒng)的編程方法是非常冗余和繁瑣的。由于LINQ是.NET編程語(yǔ)言中的一部分,開(kāi)發(fā)人員就能通過(guò)編程語(yǔ)言進(jìn)行篩選,LINQ查詢(xún)語(yǔ)句示例代碼如下所示。varst=fromsinstrwheres.Contains("學(xué)習(xí)")selects;2.使用SQLServer在傳統(tǒng)的數(shù)據(jù)庫(kù)開(kāi)發(fā)中,如果需要篩選某個(gè)數(shù)據(jù)庫(kù)中的數(shù)據(jù),可以通過(guò)SQL語(yǔ)句進(jìn)行篩選。在ADO.NET中,首先需要從數(shù)據(jù)庫(kù)中查詢(xún)數(shù)據(jù),查詢(xún)后就必須將數(shù)據(jù)填充到數(shù)據(jù)集中,然后在數(shù)據(jù)集中進(jìn)行數(shù)據(jù)遍歷,示例代碼如下所示。try{SqlConnectioncon=newSqlConnection("server='(local)';database='student';uid='sa';pwd='sa'"); //創(chuàng)建連接con.Open(); //打開(kāi)連接stringstrsql="select*fromstudent,classwherestudent.c_id=class.c_id"; //SQL語(yǔ)句SqlDataAdapterda=newSqlDataAdapter(strsql,con); //創(chuàng)建適配器DataSetds=newDataSet(); //創(chuàng)建數(shù)據(jù)集intj=da.Fill(ds,"mytable"); //填充數(shù)據(jù)集for(inti=0;i<j;i++) //遍歷集合{Console.WriteLine(ds.Tables["mytable"].Rows[i]["S_NAME"].ToString()); //輸出對(duì)象}}catch{Console.WriteLine("數(shù)據(jù)庫(kù)連接錯(cuò)誤"); //拋出異常}上述代碼進(jìn)行數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn)和查詢(xún)。在上述代碼中,首先需要?jiǎng)?chuàng)建一個(gè)連接對(duì)象進(jìn)行數(shù)據(jù)庫(kù)連接,然后再打開(kāi)連接,打開(kāi)連接之后就要編寫(xiě)SELECT語(yǔ)句進(jìn)行數(shù)據(jù)庫(kù)查詢(xún)并填充到DataSet數(shù)據(jù)集中,并在DataSet數(shù)據(jù)集中遍歷相應(yīng)的表和列進(jìn)行數(shù)據(jù)篩選。如果要查詢(xún)C_ID為1的學(xué)生的所有姓名,有三個(gè)辦法,這三個(gè)辦法分別是:修改SQL語(yǔ)句。在循環(huán)內(nèi)進(jìn)行判斷。使用LINQ進(jìn)行查詢(xún)。修改SQL語(yǔ)句是最方便的方法,直接在SELECT語(yǔ)句中添加查詢(xún)條件WHEREC-ID=1就能夠?qū)崿F(xiàn),但是這個(gè)方法擴(kuò)展性非常的低,如果有其他需求則就需要修改SQL語(yǔ)句,也有可能造成其余代碼填充數(shù)據(jù)集后數(shù)據(jù)集內(nèi)容不同步。在循環(huán)內(nèi)進(jìn)行判斷也是一種方法,但是這個(gè)方法當(dāng)循環(huán)增加時(shí)會(huì)造成額外的性能消耗,并且當(dāng)需要擴(kuò)展時(shí),還需要修改循環(huán)代碼。最方便的就是使用LINQ進(jìn)行查詢(xún),在VisualStudio2008中提供了LINQtoSQL類(lèi)文件用于將現(xiàn)有的數(shù)據(jù)抽象成對(duì)象,這樣就符合了面向?qū)ο蟮脑瓌t,同時(shí)也能夠減少代碼,提升擴(kuò)展性。創(chuàng)建一個(gè)LINQtoSQL類(lèi)文件,直接將服務(wù)資源管理器中的相應(yīng)表拖放到LINQtoSQL類(lèi)文件可視化窗口中即可,如圖21-1所示。圖21-1創(chuàng)建LINQtoSQL文件創(chuàng)建了LINQtoSQL類(lèi)文件后,就可以直接使用LINQtoSQL類(lèi)文件提供的類(lèi)進(jìn)行查詢(xún),示例代碼如下所示。linqtosqlDataContextlq=newlinqtosqlDataContext();varmylq=fromlinlq.Studentfromclinlq.Classwherel.C_ID==cl.C_IDselectl; //執(zhí)行查詢(xún)foreach(varresultinmylq) //遍歷集合{Console.WriteLine(result.S_NAME.ToString()); //輸出對(duì)象}上述代碼只用了很短的代碼就能夠?qū)崿F(xiàn)數(shù)據(jù)庫(kù)中數(shù)據(jù)的查詢(xún)和遍歷,并且從可讀性上來(lái)說(shuō)也很容易理解,因?yàn)長(zhǎng)INQ查詢(xún)語(yǔ)句的語(yǔ)法基本與SQL語(yǔ)法相同,只要有一定的SQL語(yǔ)句基礎(chǔ)就能夠非常容易的編寫(xiě)LINQ查詢(xún)語(yǔ)句。3.?dāng)?shù)據(jù)集LINQ同樣對(duì)數(shù)據(jù)集支持查詢(xún)和篩選操作。其實(shí)數(shù)據(jù)集也是集合的表現(xiàn)形式,數(shù)據(jù)集除了能夠填充數(shù)據(jù)庫(kù)中的內(nèi)容以外,開(kāi)發(fā)人員還能夠通過(guò)對(duì)數(shù)據(jù)集的操作向數(shù)據(jù)集中添加數(shù)據(jù)和修改數(shù)據(jù)。前面的章節(jié)中已經(jīng)講到,數(shù)據(jù)集可以看作是內(nèi)存中的數(shù)據(jù)庫(kù)。數(shù)據(jù)集能夠模擬基本的數(shù)據(jù)庫(kù),包括表、關(guān)系等。這里就將SQLServer中的數(shù)據(jù)填充到數(shù)據(jù)集即可,示例代碼如下所示。try{SqlConnectioncon=newSqlConnection("server='(local)';database='student';uid='sa';pwd='sa'"); //創(chuàng)建連接con.Open(); //打開(kāi)連接stringstrsql="select*fromstudent,classwherestudent.c_id=class.c_id"; //執(zhí)行SQLSqlDataAdapterda=newSqlDataAdapter(strsql,con); //創(chuàng)建適配器DataSetds=newDataSet(); //創(chuàng)建數(shù)據(jù)集da.Fill(ds,"mytable"); //填充數(shù)據(jù)集DataTabletables=ds.Tables["mytable"]; //創(chuàng)建表vardslq=fromdintables.AsEnumerable()selectd; //執(zhí)行LINQ語(yǔ)句foreach(varresindslq){Console.WriteLine(res.Field<string>("S_NAME").ToString()); //輸出對(duì)象}}catch{Console.WriteLine("數(shù)據(jù)庫(kù)連接錯(cuò)誤");}上述代碼使用LINQ針對(duì)數(shù)據(jù)集中的數(shù)據(jù)進(jìn)行篩選和整理,同樣能夠以一種面向?qū)ο蟮乃枷脒M(jìn)行數(shù)據(jù)集中數(shù)據(jù)的篩選。在使用LINQ進(jìn)行數(shù)據(jù)集操作時(shí),LINQ不能直接從數(shù)據(jù)集對(duì)象中查詢(xún),因?yàn)閿?shù)據(jù)集對(duì)象不支持LINQ查詢(xún),所以需要使用AsEnumerable方法返回一個(gè)泛型的對(duì)象以支持LINQ的查詢(xún)操作,示例代碼如下所示。vardslq=fromdintables.AsEnumerable()selectd; //使用AsEnumerable上述代碼使用AsEnumerable方法就可以讓數(shù)據(jù)集中的表對(duì)象能夠支持LINQ查詢(xún)。21.1.3執(zhí)行LINQ查詢(xún)從上一節(jié)可以看出LINQ在編程過(guò)程中極大的方便了開(kāi)發(fā)人員對(duì)于業(yè)務(wù)邏輯的處理代碼的編寫(xiě),在傳統(tǒng)的編程方法中復(fù)雜、冗余、難以實(shí)現(xiàn)的方法在LINQ中都能很好的解決。LINQ不僅能夠像SQL語(yǔ)句一樣編寫(xiě)查詢(xún)表達(dá)式,LINQ最大的優(yōu)點(diǎn)也包括LINQ作為編程語(yǔ)言的一部分,可以使用編程語(yǔ)言提供的特性進(jìn)行LINQ條件語(yǔ)句的編寫(xiě),這就彌補(bǔ)了SQL語(yǔ)句中的一些不足。在前面的章節(jié)中將一些復(fù)雜的查詢(xún)和判斷的代碼簡(jiǎn)化成LINQ應(yīng)用后,就能夠執(zhí)行應(yīng)用程序判斷LINQ是否查詢(xún)和篩選出了所需要的值。1.?dāng)?shù)組在數(shù)組數(shù)據(jù)源中,開(kāi)發(fā)人員希望能夠篩選出大于5的元素。開(kāi)發(fā)人員將傳統(tǒng)的代碼修改成LINQ代碼并通過(guò)LINQ查詢(xún)語(yǔ)句進(jìn)行篩選,示例代碼如下所示。varst=fromsininterwheres>5selects; //執(zhí)行LINQ查詢(xún)上述代碼將查詢(xún)?cè)趇nter數(shù)組中的所有元素并返回其中元素的值大于5的元素的集合,運(yùn)行后如圖21-2所示。圖21-2遍歷數(shù)組LINQ執(zhí)行了條件語(yǔ)句并返回了元素的值大于5的元素。LINQ語(yǔ)句能夠方便的擴(kuò)展,當(dāng)有不同的需求時(shí),可以修改條件語(yǔ)句進(jìn)行邏輯判斷,例如可以篩選一個(gè)平方數(shù)為偶數(shù)的數(shù)組元素,直接修改條件即可,LINQ查詢(xún)語(yǔ)句如下所示。varst=fromsininterwhere(s*s)%2==0selects; //執(zhí)行LINQ查詢(xún)上述代碼通過(guò)條件(s*s)%2==0將數(shù)組元素進(jìn)行篩選,選擇平方數(shù)為偶數(shù)的數(shù)組元素的集合,運(yùn)行后如圖21-3所示。圖21-3更改篩選條件2.使用SQLServer在LINQtoSQL類(lèi)文件中,LINQtoSQL類(lèi)文件已經(jīng)將數(shù)據(jù)庫(kù)的模型封裝成一個(gè)對(duì)象,開(kāi)發(fā)人員能夠通過(guò)面向?qū)ο蟮乃枷朐L(fǎng)問(wèn)和整合數(shù)據(jù)庫(kù)。LINQtoSQL也對(duì)SQL做了補(bǔ)充,使用LINQtoSQL類(lèi)文件能夠執(zhí)行更強(qiáng)大的篩選,LINQ查詢(xún)語(yǔ)句代碼如下所示。varmylq=fromlinlq.Studentfromclinlq.Classwherel.C_ID==cl.C_IDselectl; //執(zhí)行LINQ查詢(xún)上述代碼從Student表和Class表中篩選了C_ID相等的學(xué)生信息,這很容易在SQL語(yǔ)句中實(shí)現(xiàn)。LINQ作為編程語(yǔ)言的一部分,可以使用更多的編程方法實(shí)現(xiàn)不同的篩選需求,例如篩選名稱(chēng)中包含“郭”字的學(xué)生的名稱(chēng)在傳統(tǒng)的SQL語(yǔ)句中就很難通過(guò)一條語(yǔ)句實(shí)現(xiàn),而在LINQ中就能夠?qū)崿F(xiàn),示例代碼如下所示。varmylq=fromlinlq.Studentfromclinlq.Classwherel.C_ID==cl.C_IDwherel.S_NAME.Contains("郭")selectl; //執(zhí)行LINQ條件查詢(xún)上述代碼使用了Contains方法判斷一個(gè)字符串中是否包含某個(gè)字符或字符串,這樣不僅方便閱讀,也簡(jiǎn)化了查詢(xún)操作,運(yùn)行后如圖21-4和圖21-5所示。圖21-4簡(jiǎn)單查詢(xún)圖21-5條件查詢(xún)LINQ返回了符合條件的元素的集合,并實(shí)現(xiàn)了篩選操作。LINQ不僅作為編程語(yǔ)言的一部分,簡(jiǎn)化了開(kāi)發(fā)人員的開(kāi)發(fā)操作,從另一方面講,LINQ也補(bǔ)充了在SQL中難以通過(guò)幾條語(yǔ)句實(shí)現(xiàn)的功能的實(shí)現(xiàn)。從上面的LINQ查詢(xún)代碼可以看出,就算是不同的對(duì)象、不同的數(shù)據(jù)源,其LINQ基本的查詢(xún)語(yǔ)法都非常相似,并且LINQ還能夠支持編程語(yǔ)言具有的特性從而彌補(bǔ)SQL語(yǔ)句的不足。在數(shù)據(jù)集的查詢(xún)中,其查詢(xún)語(yǔ)句也可以直接使用而無(wú)需大面積修改代碼,這樣代碼就具有了更高的維護(hù)性和可讀性。21.2LINQ查詢(xún)語(yǔ)法概述從上面的章節(jié)中可以看出,LINQ查詢(xún)語(yǔ)句能夠?qū)?fù)雜的查詢(xún)應(yīng)用簡(jiǎn)化成一個(gè)簡(jiǎn)單的查詢(xún)語(yǔ)句,不僅如此,LINQ還支持編程語(yǔ)言本有的特性進(jìn)行高效的數(shù)據(jù)訪(fǎng)問(wèn)和篩選。雖然LINQ在寫(xiě)法上和SQL語(yǔ)句十分相似,但是LINQ語(yǔ)句在其查詢(xún)語(yǔ)法上和SQL語(yǔ)句還是有出入的,SQL查詢(xún)語(yǔ)句如下所示。select*fromstudent,classwherestudent.c_id=class.c_id //SQL查詢(xún)語(yǔ)句上述代碼是SQL查詢(xún)語(yǔ)句,對(duì)于LINQ而言,其查詢(xún)語(yǔ)句格式如下所示。varmylq=fromlinlq.Studentfromclinlq.Classwherel.C_ID==cl.C_IDselectl; //LINQ查詢(xún)語(yǔ)句上述代碼作為L(zhǎng)INQ查詢(xún)語(yǔ)句實(shí)現(xiàn)了同SQL查詢(xún)語(yǔ)句一樣的效果,但是LINQ查詢(xún)語(yǔ)句在格式上與SQL語(yǔ)句不同,LINQ的基本格式如下所示。var<變量>=from<項(xiàng)目>in<數(shù)據(jù)源>where<表達(dá)式>orderby<表達(dá)式>LINQ語(yǔ)句不僅能夠支持對(duì)數(shù)據(jù)源的查詢(xún)和篩選,同SQL語(yǔ)句一樣,還支持ORDERBY等排序,以及投影等操作,示例查詢(xún)語(yǔ)句如下所示。varst=fromsininterwheres==3selects; //LINQ查詢(xún)varst=fromsininterwhere(s*s)%2==0orderbysdescendingselects; //LINQ條件查詢(xún)從結(jié)構(gòu)上來(lái)看,LINQ查詢(xún)語(yǔ)句同SQL查詢(xún)語(yǔ)句中比較大的區(qū)別就在于SQL查詢(xún)語(yǔ)句中的SELECT關(guān)鍵字在語(yǔ)句的前面,而在LINQ查詢(xún)語(yǔ)句中SELECT關(guān)鍵字在語(yǔ)句的后面,在其他地方?jīng)]有太大的區(qū)別,對(duì)于熟悉SQL查詢(xún)語(yǔ)句的人來(lái)說(shuō)非常容易上手。21.3基本子句既然LINQ查詢(xún)語(yǔ)句同SQL查詢(xún)語(yǔ)句一樣,能夠執(zhí)行條件、排序等操作,這些操作就需要使用WHERE、ORDERBY等關(guān)鍵字,這些關(guān)鍵字在LINQ中是基本子句。同SQL查詢(xún)語(yǔ)句中的WHERE、ORDERBY操作一樣,都為元素進(jìn)行整合和篩選。21.3.1from查詢(xún)子句from子句是LINQ查詢(xún)語(yǔ)句中最基本也是最關(guān)鍵的子句關(guān)鍵字,與SQL查詢(xún)語(yǔ)句不同的是,from關(guān)鍵字必須在LINQ查詢(xún)語(yǔ)句的開(kāi)始。1.from查詢(xún)子句基礎(chǔ)后面跟隨著項(xiàng)目名稱(chēng)和數(shù)據(jù)源,示例代碼如下所示。varlinqstr=fromlqinstrselectlq; //form子句from語(yǔ)句指定項(xiàng)目名稱(chēng)和數(shù)據(jù)源,并且指定需要查詢(xún)的內(nèi)容,其中項(xiàng)目名稱(chēng)作為數(shù)據(jù)源的一部分而存在,用于表示和描述數(shù)據(jù)源中的每個(gè)元素,而數(shù)據(jù)源可以是數(shù)組、集合、數(shù)據(jù)庫(kù)甚至是XML。值得一提的是,from子句的數(shù)據(jù)源的類(lèi)型必須為IEnumerable、IEnumerable<T>類(lèi)型或者是IEnumerable、IEnumerable<T>的派生類(lèi),否則from不能夠支持LINQ查詢(xún)語(yǔ)句。在.NETFramework中泛型編程中,List(可通過(guò)索引的強(qiáng)類(lèi)型列表)也能夠支持LINQ查詢(xún)語(yǔ)句的from關(guān)鍵字,因?yàn)長(zhǎng)ist實(shí)現(xiàn)了IEnumerable、IEnumerable<T>類(lèi)型,在LINQ中可以對(duì)List類(lèi)進(jìn)行查詢(xún),示例代碼如下所示。staticvoidMain(string[]args){List<string>MyList=newList<string>(); //創(chuàng)建一個(gè)列表項(xiàng)MyList.Add("guojing"); //添加一項(xiàng)MyList.Add("wujunmin"); //添加一項(xiàng)MyList.Add("muqing"); //添加一項(xiàng)varlinqstr=fromlinMyListselectl; //LINQ查詢(xún)foreach(varelementinlinqstr) //遍歷集合{Console.WriteLine(element.ToString()); //輸出對(duì)象}Console.ReadKey();}上述代碼創(chuàng)建了一個(gè)列表項(xiàng)并向列表中添加若干項(xiàng)進(jìn)行LINQ查詢(xún)。由于List<T>實(shí)現(xiàn)了IEnumerable、IEnumerable<T>,所以L(fǎng)ist<T>列表項(xiàng)可以支持LINQ查詢(xún)語(yǔ)句的from關(guān)鍵字,如圖21-6所示。圖21-6from子句顧名思義,from語(yǔ)句可以被理解為“來(lái)自”,而in可以被理解為“在哪個(gè)數(shù)據(jù)源中”,這樣from語(yǔ)句就很好理解了,如fromlinMyListselectl語(yǔ)句可以翻譯成“找到來(lái)自MyList數(shù)據(jù)源中的集合l”,這樣就能夠更加方便的理解from語(yǔ)句。2.from查詢(xún)子句嵌套查詢(xún)?cè)赟QL語(yǔ)句中,為了實(shí)現(xiàn)某一功能,往往需要包含多個(gè)條件,以及包含多個(gè)SQL子句嵌套。在LINQ查詢(xún)語(yǔ)句中,并沒(méi)有and關(guān)鍵字為復(fù)合查詢(xún)提供功能。如果需要進(jìn)行復(fù)雜的復(fù)合查詢(xún),可以在from子句中嵌套另一個(gè)from子句即可,示例代碼如下所示。varlinqstr=fromlqinstrfromminstr2selectlq; //使用嵌套查詢(xún)上述代碼就使用了一個(gè)嵌套查詢(xún)進(jìn)行LINQ查詢(xún)。在有多個(gè)數(shù)據(jù)源或者包括多個(gè)表的數(shù)據(jù)需要查詢(xún)時(shí),可以使用LINQfrom子句嵌套查詢(xún),數(shù)據(jù)源示例代碼如下所示。List<string>MyList=newList<string>(); //創(chuàng)建一個(gè)數(shù)據(jù)源MyList.Add("guojing"); //添加一項(xiàng)MyList.Add("wujunmin"); //添加一項(xiàng)MyList.Add("muqing"); //添加一項(xiàng)MyList.Add("yuwen"); //添加一項(xiàng)List<string>MyList2=newList<string>(); //創(chuàng)建另一個(gè)數(shù)據(jù)源MyList2.Add("guojing'sphone"); //添加一項(xiàng)MyList2.Add("wujunmin'sphone"); //添加一項(xiàng)MyList2.Add("muqing'sphone"); //添加一項(xiàng)MyList2.Add("lupan'sphone"); //添加一項(xiàng)上述代碼創(chuàng)建了兩個(gè)數(shù)據(jù)源,其中一個(gè)數(shù)據(jù)源存放了聯(lián)系人的姓名的拼音名稱(chēng),另一個(gè)則存放了聯(lián)系人的電話(huà)信息。為了方便的查詢(xún)?cè)跀?shù)據(jù)源中“聯(lián)系人”和“聯(lián)系人電話(huà)”都存在并且匹配的數(shù)據(jù),就需要使用from子句嵌套查詢(xún),示例代碼如下所示。varlinqstr=fromlinMyListfromminMyList2wherem.Contains(l)selectl; //from子句嵌套查詢(xún)foreach(varelementinlinqstr) //遍歷集合元素{Console.WriteLine(element.ToString()); //輸出對(duì)象}Console.ReadKey();上述代碼使用了LINQ語(yǔ)句進(jìn)行嵌套查詢(xún),嵌套查詢(xún)?cè)贚INQ中會(huì)被經(jīng)常使用到,因?yàn)殚_(kāi)發(fā)人員常常遇到需要面對(duì)多個(gè)表多個(gè)條件,以及不同數(shù)據(jù)源或數(shù)據(jù)源對(duì)象的情況,使用LINQ查詢(xún)語(yǔ)句的嵌套查詢(xún)可以方便的在不同的表和數(shù)據(jù)源對(duì)象之間建立關(guān)系。21.3.2where條件子句在SQL查詢(xún)語(yǔ)句中可以使用where子句進(jìn)行數(shù)據(jù)的篩選,在LINQ中同樣包括where子句進(jìn)行數(shù)據(jù)源中數(shù)據(jù)的篩選。where子句指定了篩選的條件,這也就是說(shuō)在where子句中的代碼段必須返回布爾值才能夠進(jìn)行數(shù)據(jù)源的篩選,示例代碼如下所示。varlinqstr=fromlinMyListwherel.Length>5selectl; //編寫(xiě)where子句LINQ查詢(xún)語(yǔ)句可以包含一個(gè)或多個(gè)where子句,而where子句可以包含一個(gè)或多個(gè)布爾值變量,為了查詢(xún)數(shù)據(jù)源中姓名的長(zhǎng)度在6之上的姓名,可以使用where子句進(jìn)行查詢(xún),示例代碼如下所示。staticvoidMain(string[]args){List<string>MyList=newList<string>(); //創(chuàng)建List對(duì)象MyList.Add("guojing"); //添加一項(xiàng)MyList.Add("wujunmin"); //添加一項(xiàng)MyList.Add("muqing"); //添加一項(xiàng)MyList.Add("yuwen"); //添加一項(xiàng)varlinqstr=fromlinMyListwherel.Length>6selectl; //執(zhí)行where查詢(xún)foreach(varelementinlinqstr) //遍歷集合{Console.WriteLine(element.ToString()); //輸出對(duì)象}Console.ReadKey();}上述代碼添加了數(shù)據(jù)源之后,通過(guò)where子句在數(shù)據(jù)源中進(jìn)行條件查詢(xún),LINQ查詢(xún)語(yǔ)句會(huì)遍歷數(shù)據(jù)源中的數(shù)據(jù)并進(jìn)行判斷,如果返回值為true,則會(huì)在linqstr集合中添加該元素,運(yùn)行后如圖21-7所示。圖21-7where子句查詢(xún)當(dāng)需要多個(gè)where子句進(jìn)行復(fù)合條件查詢(xún)時(shí),可以使用“&&”進(jìn)行where子句的整合,示例代碼如下所示。staticvoidMain(string[]args){List<string>MyList=newList<string>(); //創(chuàng)建List對(duì)象MyList.Add("guojing"); //添加一項(xiàng)MyList.Add("wujunmin"); //添加一項(xiàng)MyList.Add("muqing"); //添加一項(xiàng)MyList.Add("guomoruo"); //添加一項(xiàng)MyList.Add("lupan"); //添加一項(xiàng)MyList.Add("guof"); //添加一項(xiàng)varlinqstr=fromlinMyListwhere(l.Length>6&&l.Contains("guo"))||l=="lupan"selectl;//復(fù)合查詢(xún)foreach(varelementinlinqstr) //遍歷集合{Console.WriteLine(element.ToString()); //輸出對(duì)象}Console.ReadKey();}上述代碼進(jìn)行了多條件的復(fù)合查詢(xún),查詢(xún)姓名長(zhǎng)度大于6并且姓名中包含guo的姓或者姓名是“l(fā)upan”的人,運(yùn)行后如圖21-8所示。圖21-8復(fù)合where子句查詢(xún)復(fù)合where子句查詢(xún)通常用于同一個(gè)數(shù)據(jù)源中的數(shù)據(jù)查詢(xún),當(dāng)需要在同一個(gè)數(shù)據(jù)源中進(jìn)行篩選查詢(xún)時(shí),可以使用where子句進(jìn)行單個(gè)或多個(gè)where子句條件查詢(xún),where子句能夠?qū)?shù)據(jù)源中的數(shù)據(jù)進(jìn)行篩選并將復(fù)合條件的元素返回到集合中。21.3.3select選擇子句select子句同from子句一樣,是LINQ查詢(xún)語(yǔ)句中必不可少的關(guān)鍵字,select子句在LINQ查詢(xún)語(yǔ)句中是必須的,示例代碼如下所示。varlinqstr=fromlqinstrselectlq; //編寫(xiě)選擇子句上述代碼中包括三個(gè)變量,這三個(gè)變量分別為linqstr、lq、str。其中str是數(shù)據(jù)源,linqstr是數(shù)據(jù)源中滿(mǎn)足查詢(xún)條件的集合,而lq也是一個(gè)集合,這個(gè)集合來(lái)自數(shù)據(jù)源。在LINQ查詢(xún)語(yǔ)句中必須包含select子句,若不包含select子句則系統(tǒng)會(huì)拋出異常(除特殊情況外)。select語(yǔ)句指定了返回到集合變量中的元素是來(lái)自哪個(gè)數(shù)據(jù)源的,示例代碼如下所示。staticvoidMain(string[]args){List<string>MyList=newList<string>(); //創(chuàng)建ListMyList.Add("guojing"); //添加一項(xiàng)MyList.Add("wujunmin"); //添加一項(xiàng)MyList.Add("guomoruo"); //添加一項(xiàng)List<string>MyList2=newList<string>(); //創(chuàng)建ListMyList2.Add("guojing'sphone"); //添加一項(xiàng)MyList2.Add("wujunmin'sphone"); //添加一項(xiàng)MyList2.Add("lupan'sphone"); //添加一項(xiàng)varlinqstr=fromlinMyListfromminMyList2wherem.Contains(l)selectl; //selectl變量foreach(varelementinlinqstr) //遍歷集合{Console.WriteLine(element.ToString()); //輸出集合內(nèi)容}Console.ReadKey(); //等待用戶(hù)按鍵}上述代碼從兩個(gè)數(shù)據(jù)源中篩選數(shù)據(jù),并通過(guò)select返回集合元素,運(yùn)行后如圖21-9所示。圖21-9select子句如果將select子句后面的項(xiàng)目名稱(chēng)更改,則結(jié)果可能不同,更改LINQ查詢(xún)子句代碼如下所示。varlinqstr=fromlinMyListfromminMyList2wherem.Contains(l)selectm; //使用select上述LINQ查詢(xún)子句并沒(méi)有selectl變量中的集合元素,而是選擇了m集合元素,則返回的應(yīng)該是MyList2數(shù)據(jù)源中的集合元素,運(yùn)行后如圖21-10所示。圖21-10select子句對(duì)于不同的select對(duì)象返回的結(jié)果也不盡相同,當(dāng)開(kāi)發(fā)人員需要進(jìn)行復(fù)合查詢(xún)時(shí),可以通過(guò)select語(yǔ)句返回不同的復(fù)合查詢(xún)對(duì)象,這在多數(shù)據(jù)源和多數(shù)據(jù)對(duì)象查詢(xún)中是非常有幫助的。21.3.4group分組子句在LINQ查詢(xún)語(yǔ)句中,group子句對(duì)from語(yǔ)句執(zhí)行查詢(xún)的結(jié)果進(jìn)行分組,并返回元素類(lèi)型為IGrouping<TKey,TElement>的對(duì)象序列。group子句支持將數(shù)據(jù)源中的數(shù)據(jù)進(jìn)行分組。但進(jìn)行分組前,數(shù)據(jù)源必須支持分組操作才可使用group語(yǔ)句進(jìn)行分組處理,示例代碼如下所示。publicclassPerson{publicintage; //分組條件publicstringname; //創(chuàng)建姓名字段publicPerson(intage,stringname) //構(gòu)造函數(shù){this.age=age; //構(gòu)造屬性值age=name; //構(gòu)造屬性值name}}上述代碼設(shè)計(jì)了一個(gè)類(lèi)用于描述聯(lián)系人的姓名和年級(jí),并且按照年級(jí)進(jìn)行分組,這樣數(shù)據(jù)源就能夠支持分組操作。注意:雖然數(shù)組也可以進(jìn)行分組操作,因?yàn)槠浣^大部分?jǐn)?shù)據(jù)源都能夠支持分組操作,但是數(shù)組等數(shù)據(jù)源進(jìn)行分組操作可能是沒(méi)有意義的。這里同樣可以通過(guò)List列表以支持LINQ查詢(xún),示例代碼如下所示。staticvoidMain(string[]args){List<Person>PersonList=newList<Person>();PersonList.Add(newPerson(21,"limusha")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(21,"guojing")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(22,"wujunmin")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(22,"lupan")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(23,"yuwen")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象vargl=frompinPersonListgrouppbyp.age; //使用group子句進(jìn)行分組foreach(varelementingl) //遍歷集合{foreach(Personpinelement) //遍歷集合{Console.WriteLine(.ToString()); //輸出對(duì)象}}Console.ReadKey();}上述代碼使用了group子句進(jìn)行數(shù)據(jù)分組,實(shí)現(xiàn)了分組的功能,運(yùn)行后如圖21-11所示。圖21-11group子句正如圖21-11所示,group子句將數(shù)據(jù)源中的數(shù)據(jù)進(jìn)行分組,在遍歷數(shù)據(jù)元素時(shí),并不像前面的章節(jié)那樣直接對(duì)元素進(jìn)行遍歷,因?yàn)間roup子句返回的是元素類(lèi)型為IGrouping<TKey,TElement>的對(duì)象序列,必須在循環(huán)中嵌套一個(gè)對(duì)象的循環(huán)才能夠查詢(xún)相應(yīng)的數(shù)據(jù)元素。在使用group子句時(shí),LINQ查詢(xún)子句的末尾并沒(méi)有select子句,因?yàn)間roup子句會(huì)返回一個(gè)對(duì)象序列,通過(guò)循環(huán)遍歷才能夠在對(duì)象序列中尋找到相應(yīng)的對(duì)象的元素,如果使用group子句進(jìn)行分組操作,可以不使用select子句。21.3.5orderby排序子句在SQL查詢(xún)語(yǔ)句中,常常需要對(duì)現(xiàn)有的數(shù)據(jù)元素進(jìn)行排序,例如注冊(cè)用戶(hù)的時(shí)間,以及新聞列表的排序,這樣能夠方便用戶(hù)在應(yīng)用程序使用過(guò)程中快速獲取需要的信息。在LINQ查詢(xún)語(yǔ)句中同樣支持排序操作以提取用戶(hù)需要的信息。在LINQ語(yǔ)句中,orderby是一個(gè)詞組而不是分開(kāi)的,orderby能夠支持對(duì)象的排序,例如按照用戶(hù)的年齡進(jìn)行排序時(shí)就可以使用orderby關(guān)鍵字,示例代碼如下所示。publicclassPerson //創(chuàng)建對(duì)象{publicintage; //創(chuàng)建字段publicstringname; //創(chuàng)建字段publicPerson(intage,stringname) //構(gòu)造函數(shù){this.age=age; //賦值字段=name;}}上述代碼同樣設(shè)計(jì)了一個(gè)Person類(lèi),并通過(guò)age、name字段描述類(lèi)對(duì)象。使用LINQ,同樣要使用List類(lèi)作為對(duì)象的容器并進(jìn)行其中元素的查詢(xún),示例代碼如下所示。classProgram{staticvoidMain(string[]args){List<Person>PersonList=newList<Person>(); //創(chuàng)建對(duì)象列表PersonList.Add(newPerson(21,"limusha")); //年齡為21PersonList.Add(newPerson(23,"guojing")); //年齡為23PersonList.Add(newPerson(22,"wujunmin")); //年齡為22PersonList.Add(newPerson(25,"lupan")); //年齡為25PersonList.Add(newPerson(24,"yuwen")); //年齡為24vargl=frompinPersonListorderbyp.ageselectp; //執(zhí)行排序操作foreach(varelementingl) //遍歷集合{Console.WriteLine(.ToString()); //輸出對(duì)象}Console.ReadKey();}}上述代碼并沒(méi)有按照順序?qū)ist容器添加對(duì)象,其中數(shù)據(jù)的顯示并不是按照順序來(lái)顯示的。使用orderby關(guān)鍵字能夠指定集合中的元素的排序規(guī)則,上述代碼按照年齡的大小進(jìn)行排序,運(yùn)行后如圖21-12所示。圖21-12orderby子句orderby子句同樣能夠?qū)崿F(xiàn)倒序排列,倒序排列在應(yīng)用程序開(kāi)發(fā)過(guò)程中應(yīng)用的非常廣泛,例如新聞等。用戶(hù)關(guān)心的都是當(dāng)天的新聞而不是很久以前發(fā)布的某個(gè)新聞,如果管理員發(fā)布了一個(gè)新的新聞,顯示在最上方的應(yīng)該是最新的新聞。在orderby子句中可以使用descending關(guān)鍵字進(jìn)行倒序排列,示例代碼如下所示。vargl=frompinPersonListorderbyp.agedescendingselectp; //orderby語(yǔ)句上述代碼將用戶(hù)的信息按照其年齡的大小倒序排列,運(yùn)行如圖21-13所示。圖21-13orderby子句倒序orderby子句同樣能夠進(jìn)行多個(gè)條件排序,如果需要使用orderby子句進(jìn)行多個(gè)條件排序,只需要將這些條件用“,”號(hào)分割即可,示例代碼如下所示。vargl=frompinPersonListorderbyp.agedescending,selectp; //orderby語(yǔ)句21.3.6into連接子句into子句通常和group子句一起使用,通常情況下,LINQ查詢(xún)語(yǔ)句中無(wú)需into子句,但是如果需要對(duì)分組中的元素進(jìn)行操作,則需要使用into子句。into語(yǔ)句能夠創(chuàng)建臨時(shí)標(biāo)識(shí)符用于保存查詢(xún)的集合,示例代碼如下所示。staticvoidMain(string[]args){List<Person>PersonList=newList<Person>(); //創(chuàng)建對(duì)象列表PersonList.Add(newPerson(21,"limusha")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(21,"guojing")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(22,"wujunmin")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(22,"lupan")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象PersonList.Add(newPerson(23,"yuwen")); //通過(guò)構(gòu)造函數(shù)構(gòu)造新對(duì)象vargl=frompinPersonListgrouppbyp.ageintoxselectx; //使用into子句創(chuàng)建標(biāo)識(shí)foreach(varelementingl) //遍歷集合{foreach(Personpinelement) //遍歷集合{Console.WriteLine(.ToString()); //輸出對(duì)象}}Console.ReadKey();}上述代碼通過(guò)使用into子句創(chuàng)建標(biāo)識(shí),從LINQ查詢(xún)語(yǔ)句中可以看出,查詢(xún)后返回的是一個(gè)集合變量x而不是p,但是編譯能夠通過(guò)并且能夠執(zhí)行查詢(xún),這說(shuō)明LINQ查詢(xún)語(yǔ)句將查詢(xún)的結(jié)果填充到了臨時(shí)標(biāo)識(shí)符對(duì)象x中并返回查詢(xún)集合給gl集合變量,運(yùn)行結(jié)果如圖21-14所示。圖21-14into子句注意:into子句必須以select、group等子句作為結(jié)尾子句,否則會(huì)拋出異常。21.3.7join連接子句在數(shù)據(jù)庫(kù)的結(jié)構(gòu)中,通常表與表之間有著不同的聯(lián)系,這些聯(lián)系決定了表與表之間的依賴(lài)關(guān)系。在LINQ中同樣也可以使用join子句對(duì)有關(guān)系的數(shù)據(jù)源或數(shù)據(jù)對(duì)象進(jìn)行查詢(xún),但首先這兩個(gè)數(shù)據(jù)源必須要有一定的聯(lián)系,示例代碼如下所示。publicclassPerson //描述“人”對(duì)象{publicintage; //描述“年齡”字段publicstringname; //描述“姓名”字段publicstringcid; //描述“車(chē)ID”字段publicPerson(intage,stringname,intcid) //構(gòu)造函數(shù){this.age=age; //初始化=name; //初始化this.cid=cid;}}publicclassCarInformaion //描述“車(chē)”對(duì)象{publicintcid; //描述“車(chē)ID”字段publicstringtype; //描述“車(chē)類(lèi)型”字段publicCarInformaion(intcid,stringtype) //初始化構(gòu)造函數(shù){this.cid=cid; //初始化this.type=type; //初始化}}上述代碼創(chuàng)建了兩個(gè)類(lèi),這兩個(gè)類(lèi)分別用來(lái)描述“人”這個(gè)對(duì)象和“車(chē)”這個(gè)對(duì)象,CarInformation對(duì)象可以用來(lái)描述車(chē)的編號(hào)以及車(chē)的類(lèi)型,而Person類(lèi)可以用來(lái)描述人購(gòu)買(mǎi)了哪個(gè)牌子的車(chē),這就確定了這兩個(gè)類(lèi)之間的依賴(lài)關(guān)系。而在對(duì)象描述中,如果將CarInformation類(lèi)的屬性和字段放置到Person類(lèi)的屬性中,會(huì)導(dǎo)致類(lèi)設(shè)計(jì)臃腫,同時(shí)也沒(méi)有很好的描述該對(duì)象。對(duì)象創(chuàng)建完畢就可以使用List類(lèi)創(chuàng)建對(duì)象,示例代碼如下所示。List<Person>PersonList=newList<Person>(); //創(chuàng)建List類(lèi)PersonList.Add(newPerson(21,"limusha",1)); //購(gòu)買(mǎi)車(chē)ID為1的人PersonList.Add(newPerson(21,"guojing",2)); //購(gòu)買(mǎi)車(chē)ID為2的人PersonList.Add(newPerson(22,"wujunmin",3)); //購(gòu)買(mǎi)車(chē)ID為3的人List<CarInformaion>CarList=newList<CarInformaion>();CarList.Add(1,"寶馬"); //車(chē)ID為1的基本信息CarList.Add(2,"奇瑞");上述代碼分別使用了List類(lèi)進(jìn)行對(duì)象的初始化,使用join子句就能夠進(jìn)行不同數(shù)據(jù)源中數(shù)據(jù)關(guān)聯(lián)的操作和外連接,示例代碼如下所示。staticvoidMain(string[]args){List<Person>PersonList=newList<Person>(); //創(chuàng)建List類(lèi)PersonList.Add(newPerson(21,"limusha",1)); //購(gòu)買(mǎi)車(chē)ID為1的人PersonList.Add(newPerson(21,"guojing",2)); //購(gòu)買(mǎi)車(chē)ID為2的人PersonList.Add(newPerson(22,"wujunmin",3)); //購(gòu)買(mǎi)車(chē)ID為3的人List<CarInformaion>CarList=newList<CarInformaion>(); //創(chuàng)建List類(lèi)CarList.Add(newCarInformaion(1,"寶馬")); //車(chē)ID為1的車(chē)CarList.Add(newCarInformaion(2,"奇瑞")); //車(chē)ID為2的車(chē)vargl=frompinPersonListjoincarinCarListonp.cidequalscar.cidselectp;//使用join子句foreach(varelementingl) //遍歷集合{Console.WriteLine(.ToString()); //輸出對(duì)象}Console.ReadKey();}上述代碼使用join子句進(jìn)行不同數(shù)據(jù)源之間關(guān)系的創(chuàng)建,其用法同SQL查詢(xún)語(yǔ)句中的INNERJOIN查詢(xún)語(yǔ)句相似,運(yùn)行后如圖21-15所示。圖21-15join查詢(xún)子句21.3.8let臨時(shí)表達(dá)式子句在LINQ查詢(xún)語(yǔ)句中,let關(guān)鍵字可以看作是在表達(dá)式中創(chuàng)建了一個(gè)臨時(shí)的變量用于保存表達(dá)式的結(jié)果,但是let子句指定的范圍變量的值只能通過(guò)初始化操作進(jìn)行賦值,一旦初始化之后就無(wú)法再次進(jìn)行更改操作。示例代碼如下所示。staticvoidMain(string[]args){List<Person>PersonList=newList<Person>(); //創(chuàng)建List類(lèi)PersonList.Add(newPerson(21,"limusha",1)); //購(gòu)買(mǎi)車(chē)ID為1的人PersonList.Add(newPerson(21,"guojing",2)); //購(gòu)買(mǎi)車(chē)ID為2的人PersonList.Add(newPerson(22,"wujunmin",3)); //購(gòu)買(mǎi)車(chē)ID為3的人List<CarInformaion>CarList=newList<CarInformaion>(); //創(chuàng)建List類(lèi)CarList.Add(newCarInformaion(1,"寶馬")); //車(chē)ID為1的車(chē)CarList.Add(newCarInformaion(2,"奇瑞")); //車(chē)ID為2的車(chē)vargl=frompinPersonListletcar=fromcinCarListselectc.cidselectp; //使用let語(yǔ)句foreach(varelementingl) //遍歷集合{Console.WriteLine(.ToString()); //輸出對(duì)象}Console.ReadKey();}let就相當(dāng)于是一個(gè)中轉(zhuǎn)變量,用于臨時(shí)存儲(chǔ)表達(dá)式的值,在LINQ查詢(xún)語(yǔ)句中,其中的某些過(guò)程的值可以通過(guò)let進(jìn)行保存。而簡(jiǎn)單的說(shuō),let就是臨時(shí)變量,如x=1+1、y=x+2這樣,其中x就相當(dāng)于是一個(gè)let變量,上述代碼運(yùn)行后如圖21-16所示。圖21-16let子句21.4LINQ查詢(xún)操作前面介紹了LINQ的一些基本的語(yǔ)法,以及LINQ常用的查詢(xún)子句進(jìn)行數(shù)據(jù)的訪(fǎng)問(wèn)和整合,甚至建立數(shù)據(jù)源對(duì)象和數(shù)據(jù)源對(duì)象之間的關(guān)聯(lián),使用LINQ查詢(xún)子句能夠?qū)崿F(xiàn)不同的功能,包括投影、排序和聚合等,本節(jié)開(kāi)始介紹LINQ的查詢(xún)操作。21.4.1LINQ查詢(xún)概述LINQ不僅提供了強(qiáng)大的查詢(xún)表達(dá)式為開(kāi)發(fā)人員對(duì)數(shù)據(jù)源進(jìn)行查詢(xún)和篩選操作提供遍歷,LINQ還提供了大量的查詢(xún)操作,這些操作通過(guò)實(shí)現(xiàn)IEnumerable<T>或IQueryable<T>提供的接口實(shí)現(xiàn)了投影、排序、聚合等操作。通過(guò)使用LINQ提供的查詢(xún)方法,能夠快速的實(shí)現(xiàn)投影、排序等操作。由于LINQ查詢(xún)操作實(shí)現(xiàn)了IEnumerable<T>或IQueryable<T>接口,所以L(fǎng)INQ查詢(xún)操作能夠通過(guò)接口中特定的方法進(jìn)行查詢(xún)和篩選,可以直接使用數(shù)據(jù)源對(duì)象變量的方法進(jìn)行操作。在LINQ查詢(xún)操作的方法中,需要大量的使用Lambda表達(dá)式實(shí)現(xiàn)委托,這就從另一個(gè)方面說(shuō)明了Lambda表達(dá)式的重要性。示例代碼如下所示。int[]inter={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //創(chuàng)建數(shù)組varlint=inter.Select(i=>i); //使用Lambda上述代碼使用了Select方法進(jìn)行投影操作,在投影操作的參數(shù)中使用Lambda表達(dá)式表示了如何實(shí)現(xiàn)數(shù)據(jù)篩選。LINQ查詢(xún)操作不僅包括Select投影操作,還包括排序、聚合等操作,LINQ常用操作如下所示。Count:計(jì)算集合中元素的數(shù)量,或者計(jì)算滿(mǎn)足條件的集合的元素的數(shù)量。GroupBy:實(shí)現(xiàn)對(duì)集合中的元素進(jìn)行分組的操作。Max:獲取集合中元素的最大值。Min:獲取集合中元素的最小值。Select:執(zhí)行投影操作。SelectMany:執(zhí)行投影操作,可以為多個(gè)數(shù)據(jù)源進(jìn)行投影操作。Where:執(zhí)行篩選操作。LINQ不只提供上述這些常用的查詢(xún)操作方法,還提供更多的查詢(xún)方法,由于本書(shū)篇幅有限,只講解一些常用的查詢(xún)方法。21.4.2投影操作和SQL查詢(xún)語(yǔ)句中的SELECT基本類(lèi)似,投影操作能夠指定數(shù)據(jù)源并選擇相應(yīng)的數(shù)據(jù)源,在LINQ中常用的投影操作包括Select和SelectMany。1.Select選擇子句Select操作能夠?qū)⒓现械脑赝队暗叫碌募现腥?,并能夠指定元素的?lèi)型和表現(xiàn)形式,示例代碼如下所示。staticvoidMain(string[]args){int[]inter={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //創(chuàng)建數(shù)組varlint=inter.Select(i=>i); //Select操作foreach(varminlint) //遍歷集合{Console.WriteLine(m.ToString()); //輸出對(duì)象}Console.ReadKey();}上述代碼將數(shù)據(jù)源進(jìn)行了投影操作,使用Select進(jìn)行投影操作非常簡(jiǎn)單,其作用同SQL語(yǔ)句中的SELECT語(yǔ)句十分相似,上述代碼將集合中的元素進(jìn)行投影并將符合條件的元素投影到新的集合中l(wèi)int去。2.SelectMany多重選擇子句SelectMany和Select的用法基本相同,但是SelectMany與Select相比可以選擇多個(gè)序列進(jìn)行投影,示例代碼如下所示。staticvoidMain(string[]args){int[]inter={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //創(chuàng)建數(shù)組int[]inter2={21,22,23,24,25,26}; //創(chuàng)建數(shù)組List<int[]>list=newList<int[]>(); //創(chuàng)建Listlist.Add(inter); //添加對(duì)象list.Add(inter2); //添加對(duì)象varlint=list.SelectMany(i=>i); //SelectMany操作foreach(varminlint) //遍歷集合{

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論