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

下載本文檔

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

文檔簡介

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

溫馨提示

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

評論

0/150

提交評論