查詢是一組指令,描述要從給定數據源(或源)檢索的數據以及返回的數據應具備的形狀和組織。 查詢與它生成的結果不一樣。html
一般狀況下,源數據按邏輯方式組織爲相同類型的元素的序列。 例如,SQL 數據庫表包含行的序列。 在 XML 文件中,存在 XML 元素的「序列」(儘管這些元素在樹結構按層次結構進行組織)。 內存中集合包含對象的序列。數據庫
從應用程序的角度來看,原始源數據的特定類型和結構並不重要。 應用程序始終將源數據視爲 IEnumerable<T> 或 IQueryable<T> 集合。 例如在 LINQ to XML 中,源數據顯示爲 IEnumerable
<XElement>。express
對於此源序列,查詢可能會執行三種操做之一:編程
檢索元素的子集以生成新序列,而不修改各個元素。 查詢而後可能以各類方式對返回的序列進行排序或分組,以下面的示例所示(假定 scores
是 int[]
):api
IEnumerable<int> highScoresQuery = from score in scores where score > 80 orderby score descending select score;
int
到 string
的投影。 請注意 highScoresQuery
的新類型。IEnumerable<string> highScoresQuery2 = from score in scores where score > 80 orderby score descending select $"The score is {score}";
檢索有關源數據的單獨值,如:數組
與特定條件匹配的元素數。ide
具備最大或最小值的元素。ui
與某個條件匹配的第一個元素,或指定元素集中特定值的總和。 例如,下面的查詢從 scores
整數數組返回大於 80 的分數的數量:spa
int highScoreCount = (from score in scores where score > 80 select score) .Count();
在前面的示例中,請注意在調用 Count
方法以前,在查詢表達式兩邊使用了括號。也能夠經過使用新變量存儲具體結果,來表示此行爲。 這種方法更具可讀性,由於它使存儲查詢的變量與存儲結果的查詢分開。code
IEnumerable<int> highScoresQuery3 = from score in scores where score > 80 select score; int scoreCount = highScoresQuery3.Count();
在上面的示例中,查詢在 Count
調用中執行,由於 Count
必須循環訪問結果才能肯定 highScoresQuery
返回的元素數。
from
子句與最後一個 select
或 group
子句之間,能夠包含如下這些可選子句中的一個或多個:where、orderby、join、let,甚至是其餘 from 子句。 還可使用 into 關鍵字,使 join
或 group
子句的結果能夠充當相同查詢表達式中的其餘查詢子句的源。
在 LINQ 中,查詢變量是存儲查詢而不是查詢結果的任何變量。 更具體地說,查詢變量始終是可枚舉類型,在 foreach
語句或對其 IEnumerator.MoveNext
方法的直接調用中循環訪問時會生成元素序列。
下面的代碼示例演示一個簡單查詢表達式,它具備一個數據源、一個篩選子句、一個排序子句而且不轉換源元素。 該查詢以 select
子句結尾。
static void Main() { // 數據源 int[] scores = { 90, 71, 82, 93, 75, 82 }; // 查詢表達式 IEnumerable<int> scoreQuery = // 查詢變量 from score in scores // 必須 where score > 80 // 可選 orderby score descending // 可選 select score; // 必須以 select 或者 group 結尾 // 執行查詢併產生結果 foreach (int testScore in scoreQuery) { Console.WriteLine(testScore); } } // 輸出: 93 90 82 82
在上面的示例中,scoreQuery
是查詢變量,它有時僅僅稱爲查詢。 查詢變量不存儲在 foreach
循環生成中的任何實際結果數據。 而且當 foreach
語句執行時,查詢結果不會經過查詢變量 scoreQuery
返回。 而是經過迭代變量 testScore
返回。 scoreQuery
變量能夠在另外一個 foreach
循環中進行循環訪問。 只要既沒有修改它,也沒有修改數據源,便會生成相同結果。
查詢變量能夠存儲採用查詢語法、方法語法或是二者的組合進行表示的查詢。 在如下示例中,queryMajorCities
和 queryMajorCities2
都是查詢變量:
var cities = new City { new city(){Name = "上海",Population = 24180000}, new city(){Name = "南京",Population = 8436200}, new city(){Name = "北京",Population = 21710000}, new city(){Name = "廣州",Population = 14900000} }; // 查詢語法 IEnumerable<City> queryMajorCities = from city in cities where city.Population > 100000 select city; // 基於方法的語法 IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);
另外一方面,如下兩個示例演示不是查詢變量的變量(即便各自使用查詢進行初始化)。 它們不是查詢變量,由於它們存儲結果:
int highestScore = (from score in scores select score) .Max(); // 或者拆分表達式 IEnumerable<int> scoreQuery = from score in scores select score; int highScore = scoreQuery.Max(); // 下面的表達式返回相同的結果 int highScore = scores.Max(); List<City> largeCitiesList = (from country in countries from city in country.Cities where city.Population > 10000 select city) .ToList(); // 或者拆分表達式 IEnumerable<City> largeCitiesQuery = from country in countries from city in country.Cities where city.Population > 10000 select city; List<City> largeCitiesList2 = largeCitiesQuery.ToList();
有關表示查詢的不一樣方式的詳細信息,請參閱 LINQ 中的查詢語法和方法語法。
本文檔一般提供查詢變量的顯式類型以便顯示查詢變量與 select 子句之間的類型關係。 可是,還可使用 var 關鍵字指示編譯器在編譯時推斷查詢變量(或任何其餘局部變量)的類型。 例如,本主題中前面演示的查詢示例也可使用隱式類型化進行表示:
// 在這裏和全部查詢中使用var都是可選的。querycities是一個IEnumerable<city>就像它是顯式類型同樣 var queryCities = from city in cities where city.Population > 100000 select city;
有關詳細信息,請參閱隱式類型化局部變量和 LINQ 查詢操做中的類型關係。
查詢表達式必須以 from
子句開頭。 它指定數據源以及範圍變量。 範圍變量表示遍歷源序列時,源序列中的每一個連續元素。 範圍變量基於數據源中元素的類型進行強類型化。 在下面的示例中,由於 countries
是 Country
對象的數組,因此範圍變量也類型化爲 Country
。 由於範圍變量是強類型,因此可使用點運算符訪問該類型的任何可用成員。
IEnumerable<Country> countryAreaQuery = from country in countries where country.Area > 500000 //面積大於500000 select country;
範圍變量一直處於範圍中,直到查詢使用分號或 continuation 子句退出。
查詢表達式可能會包含多個 from
子句。 在源序列中的每一個元素自己是集合或包含集合時,可以使用其餘 from
子句。 例如,假設具備 Country
對象的集合,其中每一個對象都包含名爲 Cities
的 City
對象集合。 若要查詢每一個 Country
中的 City
對象,請使用兩個 from
子句,以下所示:
IEnumerable<City> cityQuery = from country in countries from city in country.Cities where city.Population > 10000 select city;
有關詳細信息,請參閱 from 子句。
查詢表達式必須以 group
子句或 select
子句結尾。
使用 group
子句可生成按指定鍵組織的組的序列。 鍵能夠是任何數據類型。 例如,下面的查詢會建立包含一個或多個 Country
對象而且其鍵是 char
值的組的序列。
var queryCountryGroups = from country in countries group country by country.Name[0];
有關分組的詳細信息,請參閱 group 子句。
使用 select
子句可生成全部其餘類型的序列。 簡單 select
子句只生成類型與數據源中包含的對象相同的對象的序列。 在此示例中,數據源包含 Country
對象。 orderby
子句只按新順序對元素進行排序,而 select
子句生成從新排序的 Country
對象的序列。
IEnumerable<Country> sortedQuery = from country in countries orderby country.Area select country;
select
子句能夠用於將源數據轉換爲新類型的序列。 此轉換也稱爲投影。 在下面的示例中,select
子句對只包含原始元素中的字段子集的匿名類型序列進行投影。 請注意,新對象使用對象初始值設定項進行初始化。
// 此處 var 是必須的,由於查詢返回了匿名類型 var queryNameAndPop = from country in countries select new { Name = country.Name, Pop = country.Population };
有關可使用 select
子句轉換源數據的全部方法的詳細信息,請參閱 select 子句。
能夠在 select
或 group
子句中使用 into
關鍵字建立存儲查詢的臨時標識符。 若是在分組或選擇操做以後必須對查詢執行其餘查詢操做,則能夠這樣作。 在下面的示例中,countries
按 1000 萬範圍,根據人口進行分組。 建立這些組以後,附加子句會篩選出一些組,而後按升序對組進行排序。 若要執行這些附加操做,須要由 countryGroup
表示的延續。
// 該查詢返回的類型是 IEnumerable<IGrouping<int, Country>> var percentileQuery = from country in countries let percentile = (int) country.Population / 10_000_000 group country by percentile into countryGroup where countryGroup.Key >= 20 orderby countryGroup.Key select countryGroup; // 分組是 IGrouping<int, Country> foreach (var grouping in percentileQuery) { Console.WriteLine(grouping.Key); foreach (var country in grouping) Console.WriteLine(country.Name + ":" + country.Population); }
有關詳細信息,請參閱 into。
在開頭 from
子句與結尾 select
或 group
子句之間,全部其餘子句(where
、join
、orderby
、from
、let
)都是可選的。 任何可選子句均可以在查詢正文中使用零次或屢次。
IEnumerable<City> queryCityPop = from city in cities where city.Population < 200000 && city.Population > 100000 select city;
有關詳細信息,請參閱 where 子句。
使用 orderby
子句可按升序或降序對結果進行排序。 還能夠指定次要排序順序。 下面的示例使用 Area
屬性對 country
對象執行主要排序。 而後使用 Population
屬性執行次要排序。
IEnumerable<Country> querySortedCountries = from country in countries orderby country.Area, country.Population descending select country;
ascending
關鍵字是可選的;若是未指定任何順序,則它是默認排序順序。 有關詳細信息,請參閱 orderby 子句。
使用 join
子句可基於每一個元素中指定的鍵之間的相等比較,將一個數據源中的元素與另外一個數據源中的元素進行關聯和/或合併。 在 LINQ 中,聯接操做是對元素屬於不一樣類型的對象序列執行。 聯接了兩個序列以後,必須使用 select
或 group
語句指定要存儲在輸出序列中的元素。 還可使用匿名類型將每組關聯元素中的屬性合併到輸出序列的新類型中。下面的示例關聯其 Category
屬性與 categories
字符串數組中一個類別匹配的 prod
對象。篩選出其 Category
不與 categories
中的任何字符串匹配的產品。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 關鍵字將 join
操做的結果存儲到臨時變量中來執行分組聯接。 有關詳細信息,請參閱 join 子句。
使用 let
子句可將表達式(如方法調用)的結果存儲在新範圍變量中。 在下面的示例中,範圍變量 firstName
存儲 Split
返回的字符串數組的第一個元素。
string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" }; IEnumerable<string> queryFirstNames = from name in names let firstName = name.Split(' ')[0] select firstName; foreach (string s in queryFirstNames)
Console.Write(s + " ");
//輸出: Svetlana Claire Sven Cesar
有關詳細信息,請參閱 let 子句。
查詢子句自己可能包含查詢表達式,這有時稱爲子查詢。 每一個子查詢都以本身的 from
子句開頭,該子句不必定指向第一個 from
子句中的相同數據源。 例如,下面的查詢演示在 select 語句用於檢索分組操做結果的查詢表達式。
var queryGroupMax = from student in students group student by student.GradeLevel into studentGroup select new { Level = studentGroup.Key, HighestScore = (from student2 in studentGroup select student2.Scores.Average()) .Max() };
有關詳細信息,請參閱如何:對分組操做執行子查詢。
其餘技術請參閱