cms建立網(wǎng)站鄭州百度推廣seo
什么是LINQ?
LINQ
(語言集成查詢)是將查詢功能直接集成到C#中。數(shù)據(jù)查詢表示簡單的字符串,在編譯時不會進行類型檢查和IntelliSense
(代碼補全輔助工具)支持。
在開發(fā)中,通常需要對不同類型的數(shù)據(jù)源了解不同的查詢語句,如SQL
數(shù)據(jù)庫、XML
文檔、各種Web
服務(wù)等。為了使每種類型的查詢語句統(tǒng)一,通過借助LINQ
,查詢成了最高級的語言構(gòu)造,就像類、方法、事件一樣,可以使用語言關(guān)鍵字和熟悉的運算符針對強類型化對象集合編寫查詢。LINQ
提供了針對對象、關(guān)系數(shù)據(jù)庫、XML
的查詢技術(shù)。
LINQ
最明顯的語言集成部分是查詢表達式,查詢表達式采用聲明性語法編寫,可以通過最少的代碼對數(shù)據(jù)源進行篩選、排序和分組等操作,也可以使用相同的基本查詢表達模式來查詢和轉(zhuǎn)換SQL
數(shù)據(jù)庫、ADO.NET
數(shù)據(jù)集、XML
文檔和流、.NET
集合中的數(shù)據(jù)。
SQL Server
數(shù)據(jù)庫、XML
文檔和流、ADO.NET
數(shù)據(jù)集、支持IEnumerable
或泛型IEnumerable<T>
接口的任何對象集合都可以使用LINQ查詢。
例如:
//創(chuàng)建數(shù)據(jù)源
int[] Nums = { 86, 89, 95, 93, 79, 86, 99 };//定義查詢表達式
IEnumerable<int> numQuery = from num in Numswhere num > 80select num;
//執(zhí)行查詢
foreach(int num in numQuery)
{Console.WriteLine("num={0}", num);
}
查詢表達式概述
查詢表達式可用于查詢并轉(zhuǎn)換所有啟用了LINQ
的數(shù)據(jù)源中的數(shù)據(jù)。如,通過一個查詢可以檢索數(shù)據(jù)庫中的數(shù)據(jù),并生成指定的格式(如XML
流)作為輸出。
查詢表達式容易掌握,因為大部分是熟悉的C#語法。
查詢表達式中的變量都是強類型,在大部分情況下,不需要顯示提供類型,因為編譯器可以進行自行推斷出。
只有在循環(huán)訪問查詢變量后,才會執(zhí)行查詢(如foreach
語句)。
在編譯時,查詢表達式根據(jù)C#
語法規(guī)范轉(zhuǎn)換成標準查詢運算符方法調(diào)用。在查詢中,使用的查詢語法都可以使用方法語法進行表示。但是,查詢語法的可讀性更好,更簡潔。
在編寫LINQ
查詢時盡量使用查詢語法,在必要時使用方法語法。這兩種形式在語義或性能上毫無差異,使用查詢語法比使用方法語法編寫的等同表達式具有更好的可讀性。
一次查詢操作(如Count
或Max
)沒有等效的查詢表達式字句,因此必須表示為方法調(diào)用,可以通過各種方式結(jié)合使用方法語法和查詢語法。
查詢表達式可被編譯成表達式樹或委托,具體應根據(jù)查詢類型而定。
IEnumerable<T>
查詢編譯為委托。IQueryable
和IQueryable<T>
查詢編譯為表達式樹。
查詢表達式
在進行了解之前,我們首先要思考的是:查詢是什么?及其作用是什么?
查詢是一組指令,描述要從給定的數(shù)據(jù)源中檢索數(shù)據(jù)以及返回的數(shù)據(jù)應具有的形狀和組織。查詢與它生成的結(jié)果不同。
通常情況下,源數(shù)據(jù)按邏輯方式組織為相同類型的元素序列。如,SQL
數(shù)據(jù)庫表包含行的序列。在XML
文件中,存在XML
元素的序列(這些元素在樹結(jié)構(gòu)按層次結(jié)構(gòu)進行組織)。內(nèi)存中集合包含的對象序列。
從應用程序的角度來講,原始源數(shù)據(jù)的特定類型和結(jié)構(gòu)并不重要。應用程序始終將原始數(shù)據(jù)視為IEnumerable<T>
或IQueryable<T>
集合。如,在XML
中,源數(shù)據(jù)顯示為IEnumerable<XElement>
。
查詢表達式必須以from
子句開頭,它指定數(shù)據(jù)源和范圍變量,范圍變量表示遍歷源序列時,源序列中的每個連續(xù)元素,范圍變量基于數(shù)據(jù)源中元素的類型進行強類型化。如下示例所示,countries
是Country
對象的數(shù)組,所以范圍變量的類型為Country
,又范圍變量為強類型,可以使用點運算符進行訪問成員。
IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > 500000
select country;
查詢表達式必須以select
子句或group
子句結(jié)尾。
使用select
子句可生成所有其它類型的序列,簡單的select
子句只生成類型與數(shù)據(jù)源中包含的對象相同對象的類型。如下示例中,數(shù)據(jù)源中包含Country
對象,orderby
子句只按新順序?qū)υ剡M行排序,select
子句生成重新排序的Country
對象的序列。
IEnumerable<Country> sortedQuery =
from country in countries
orderby country.Area
select country;
select
子句可以將源數(shù)據(jù)轉(zhuǎn)換為新類型的序列,此轉(zhuǎn)換稱為投影。在如下示例中,select
子句只包含原始元素中的字段子集的匿名類型序列進行投影。新對象使用對象初始值設(shè)定項進行初始化。
var queryNameAndPop =
from country in countries
select new { Name = country.Name, Pop = country.Population };
使用group
子句可以生成按指定鍵組織的組的序列,鍵可以是任意類型的數(shù)據(jù)。如下示例所示,下面的查詢會創(chuàng)建包含一個或多個country
對象,并且其鍵是char
值的組的序列。
var queryCountryGroups =
from country in countries
group country by country.Name[0];
foreach(IEnumerable<Country> country in queryCountryGroups )
{foreach(Country_country in country ){Console.WriteLine("City={0}", _country .Name);}
}
對于此源序列,查詢可能會執(zhí)行三種操作之一:
1、檢索元素的子集以生成新序列,而不修改各個元素,然后可能以各種方式對返回的序列進行排序或分組。如下所示。
IEnumerable<int> query = from num in Numswhere num > 80orderby num descendingselect num;
2、如前面的示例所示檢索元素的序列,但是將它們轉(zhuǎn)換為新類型的對象。如,查詢可以只從數(shù)據(jù)源中的某些客戶記錄檢索姓氏,或者可以檢索完整記錄,
IEnumerable<string> queryStr = from num in querywhere num > 80orderby num descendingselect string.Format("The number id {0}", num);
3、檢索有關(guān)源數(shù)據(jù)的單獨值,如:與特定條件匹配的元素數(shù);具有最大或最小值的元素;與某個條件匹配的第一個元素。如下例子所示:
int hightCount = (from num in Numswhere num > 85select num).Count();
在上面的示例中,在調(diào)用Count
方法之前,在查詢表達式兩邊使用了括號,也可以通過使用新變量存儲結(jié)果,這種寫法更具有可讀性,因為它使存儲查詢的變量與存儲結(jié)果的查詢分開,如下例子所示:
IEnumerable<int> hightQuery = from num in Numswhere num > 90select num;int hightCounts = hightQuery.Count();
查詢表達式是什么?
查詢表達式是以查詢語法表示的查詢。查詢表達式由一組類似于SQL
或XQuery
的聲明性語法所編寫的字句組成,每個字句包含一個或多個C#
表達式,而這些表達式本身可能是查詢表達式或包含查詢表達式。
查詢表達式必須以from
字句開頭,且必須以select
或group
字句結(jié)尾。在from
和select
或group
之間,可以包含以下這些可選子句中的一個或多個:where
、orderby
、join
、let
,甚至是其它from
子句。還可以使用into
關(guān)鍵字,使join
或group
子句的結(jié)果可以充當相同查詢表達式中的其它查詢表達式的源。
查詢變量
在LINQ
中,查詢變量存儲查詢而不是查詢結(jié)果的任何變量。查詢變量始終是可枚舉類型,在foreach
語句或?qū)ζ?code>IEnumerator.MoveNext方法的直接調(diào)用中循環(huán)訪問時會生成元素序列。
查詢變量可以存儲采用查詢語法、方法語法或兩者的組合進行表示的查詢,如以下示例中,majorCity
和majorCity2
都是查詢變量。
List<City> cityList = new List<City>(){new City{ Population = 1000000},new City{Population = 100000},new City{Population = 10000},new City{Population = 540000}};//查詢語法IEnumerable<City> majorCity = from city in cityListwhere city.Population > 120000select city;//方法語法IEnumerable<City> majorCity2 = cityList.Where(a => a.Population > 120000);
另一方面,以下示例演示不是查詢變量的變量(即使各自使用查詢進行初始化),它們不是查詢變量,因為它們存儲結(jié)果。
int highestScore =
(from score in scores
select score)
.Max();
// or split the expression
IEnumerable<int> scoreQuery =
from score in scores
select score;
int highScore = scoreQuery.Max();
// the following returns the same result
int highScore = scores.Max();
List<City> largeCitiesList =
(from country in countries
from city in country.Cities
where city.Population > 10000
select city)
.ToList();
// or split the expression
IEnumerable<City> largeCitiesQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
List<City> largeCitiesList2 = largeCitiesQuery.ToList();
查詢表達式可能會包含多個from
子句。在源序列中的每個元素本身就是集合或包含集合時,可以使用其它from
子句。如下示例所示,假設(shè)具有County
對象的集合,每個對象都包含名為Cities
的City
對象集合,若要查詢每個County
中的City
對象,請使用兩個from
子句。
IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
使用into
進行延續(xù)
可以在select
或group
子句中使用into
關(guān)鍵字創(chuàng)建存儲查詢的臨時標識符。如果在group
或select
操作之后必須對查詢執(zhí)行其它查詢操作,可以使用into
關(guān)鍵字。在如下示例中,countries
按1000萬范圍進行分組,創(chuàng)建這些分組之后,附加子句會篩選出一些組,然后按升序?qū)M進行排序,若要執(zhí)行這些附加操作,需要由countryGroup
表示的延續(xù)。
var percentileQuery =
from country in countries
let percentile = (int) country.Population / 10000000
group country by percentile into countryGroup
where countryGroup.Key >= 20
orderby countryGroup.Key
select countryGroup;
// grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
Console.WriteLine(grouping.Key);
foreach (var country in grouping)
Console.WriteLine(country.Name + ":" + country.Population);
}
篩選、排序和聯(lián)接
在開頭from
子句與結(jié)尾select
或group
子句之間,所有其它子句(where
、join
、orderby
、from
、let
)都是可選的,任何可選子句在查詢中可以使用零次或多次。
where子句
使用where
子句可基于一個或多個表達式,從源數(shù)據(jù)中篩選出元素。如下示例所示。
IEnumerable<City> queryCityPop =
from city in cities
where city.Population < 200000 && city.Population > 100000
select city;
orderby子句
使用orderby
子句可按升序或降序?qū)Y(jié)果進行排序,還可以指定次要排序順序。如下示例所示,使用Area
屬性對country
對象進行主要排序,Population屬性進行次要排序。
IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;
ascending
關(guān)鍵字是可選的,如果未指定任何順序,則它是默認的排序順序。
join子句
使用join
子句基于每個元素中指定鍵之間的相等比較,將一個數(shù)據(jù)源中的元素與另一個數(shù)據(jù)源中的元素進行合并或關(guān)聯(lián)。在LINQ
中,聯(lián)接操作是對不同類型的對象序列執(zhí)行,聯(lián)接兩個序列之后,必須使用select
或group
語句指定要存儲在輸出序列中的元素,還可以使用匿名類型將每組關(guān)聯(lián)元素中的屬性合并到輸出序列中的新類型。如下示例所示,關(guān)聯(lián)其Category
屬性與categories
字符串數(shù)組中一個類別匹配的prod
對象,篩選出Category
與categories
數(shù)組中任何匹配的字符串,select
語句投影其屬性取自cat
和prod
的新類型。
var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new { Category = cat, Name = prod.Name };
還可以使用into
關(guān)鍵字,將join
操作的結(jié)果存儲到臨時變量中來執(zhí)行分組聯(lián)接。
let子句
使用let
子句可將表達式(如方法調(diào)用)的結(jié)果存儲到新范圍變量中。在如下示例中,范圍變量f_name
存儲Split
返回的字符串數(shù)組中的第一個元素。
string[] str = { "kdh jsn", "lkhs nhdj", "sjjkd lsmkcj", "shdyfsh sjdnmds" };IEnumerable<string> queryName = from name in strlet f_name = name.Split(' ')[0]select f_name;foreach(string name in queryName){Console.WriteLine("name={0}", name);}
查詢表達式中的子查詢
查詢子句本身可能包含查詢表達式,也稱為子查詢。每個子查詢都是以from
子句開頭,該子句不一定指向第一個from
子句中相同的數(shù)據(jù)源。如下示例中,在select
語句用于檢索分組操作結(jié)果的查詢表達式。
var groupMax = from city in cityListgroup city by city.Population into newCityselect new{Level = newCity.Key,maxKey = (from cityMax in newCityselect cityMax.Population).Max()};
這次就先講到這里啦,下次在講解LINQ
的方法語法,熱烈歡迎各位廣大網(wǎng)友進行批評指正。