LINQ查詢表達式(1) - 查詢表達式基礎

  LINQ包括五個部分:LINQto Objects、LINQ to DataSets、LINQ to SQL、LINQ to Entities、LINQ to XML。數據庫

什麼是查詢?它有什麼用途?

  「查詢」是指一組指令,這些指令描述要從一個或多個給定數據源檢索的數據以及返回的數據應該使用的格式和組織形式。 查詢不一樣於它所產生的結果。
一般,源數據會在邏輯上組織爲相同種類的元素序列。 SQL 數據庫表包含一個行序列。 與此相似,ADO.NET DataTable 包含一個 DataRow 對象序列。 在 XML 文件中,有一個 XML 元素「序列」(不過這些元素按分層形式組織爲樹結構)。 內存中的集合包含一個對象序列。
從應用程序的角度來看,原始源數據的具體類型和結構並不重要。 應用程序始終將源數據視爲一個 IEnumerable<T> 或 IQueryable<T> 集合。 在 LINQ to XML 中,源數據顯示爲一個 IEnumerable<XElement>。 在 LINQ to DataSet 中,它是一個 IEnumerable<DataRow>。 在 LINQ to SQL 中,它是您定義用來表示 SQL 表中數據的任何自定義對象的 IEnumerable 或 IQueryable。數組

查詢結果3種:ui

  • 檢索元素子集,產生新的序列,不修改單個元素,能夠對其進行分組、排序
 IEnumerable<int> highScoresQuery =
                from score in scores
                where score > 80
                orderby score descending
                select score;

 

  • 檢索元素子集,轉換元素類型
 IEnumerable<string> highScoresQuery2 =
                from score in scores
                where score > 80
                orderby score descending
                select String.Format("The score is {0}", score);

 

  •  檢索有關源數據的單一值
int highScoreCount =
                (from score in scores
                 where score > 80
                 select score)
                 .Count();

-or-

IEnumerable<int> highScoresQuery3 =
                from score in scores
                where score > 80
                select score;

            int scoreCount = highScoresQuery3.Count();

 

什麼是查詢表達式

  「查詢表達式」是用查詢語法表示的查詢,它像其它表達式同樣,能夠應用於任何C#表達式有效的上下文中spa

  查詢表達式由一組用相似於 SQL 或 XQuery 的聲明性語法編寫的子句組成。 每一個子句又包含一個或多個 C# 表達式,而這些表達式自己又多是查詢表達式或包含查詢表達式。code

   查詢表達式必須以 from 子句開頭,而且必須以 select 或 group 子句結尾。 在第一個 from 子句和最後一個 select 或 group 子句之間,查詢表達式能夠包含一個或多個下列可選子句:where、orderby、join、let 甚至附加的 from 子句。 還可使用 into 關鍵字使 join 或 group 子句的結果可以充當同一查詢表達式中附加查詢子句的源。orm

  • 查詢變量

  存儲查詢自己,而非結果的變量,LINQ規範中,變量命名常以query結尾。  對象

  查詢變量能夠顯示或隱式聲明,使用隱式聲明用 var 關鍵字指示編譯器在編譯時推斷查詢變量的類型。blog

static void Main()
        {
            // Data source.
            int[] scores = { 90, 71, 82, 93, 75, 82 };

            // Query Expression.
            IEnumerable<int> scoreQuery = //query variable
                from score in scores //required
                where score > 80 // optional
                orderby score descending // optional
                select score; //must end with select or group

            // Execute the query to produce the results
            foreach (int testScore in scoreQuery)
            {
                Console.WriteLine(testScore);
            }                  
        }
        // Outputs: 93 90 82 82  

  上例中,查詢變量並不存儲實際的結果數據(這些數據是在 foreach 循環中產生的),另外,當 foreach 語句執行時,查詢結果並非經過查詢變量 scoreQuery 返回的。 相反,它們是經過迭代變量 testScore 返回的。 能夠在另外一個 foreach 循環中迭代 scoreQuery 變量。 只要該變量和數據源都沒有修改,該變量都將產生相同的結果。排序

  查詢變量能夠存儲用查詢語法方法語法(或兩者的組合)表示的查詢,以下:ip

        // Query syntax
            IEnumerable<City> queryMajorCities =
                from city in cities
                where city.Population > 100000
                select city;

            
            // Method-based syntax
            IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);

 

  • 開始查詢表達式(from)

  查詢表達式必須以 from 子句開頭。 它同時指定了數據源和範圍變量。 在對源序列進行遍歷的過程當中,範圍變量表示源序列中的每一個後續元素。 將根據數據源中元素的類型對範圍變量進行強類型化。 在下面的示例中,由於 countries 是 Country 對象數組,因此範圍變量也被類型化爲 Country, 這樣就可使用點運算符來訪問該類型的任何可用成員。

 IEnumerable<Country> countryAreaQuery =
                from country in countries
                where country.Area > 500000 //sq km
                select country;

  在使用分號或延續子句退出查詢以前,範圍變量將一直位於範圍中。

  查詢表達式能夠包含多個 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;

 

  • 結束查詢表達式(select 或 group)

  查詢表達式必須以 select 子句或 group 子句結尾。

  select 子句

  使用 select 子句可產生全部其餘類型的序列。 簡單的 select 子句只是產生與數據源中包含的對象具備相同類型的對象的序列。

  在此示例中,數據源包含 Country 對象。 orderby 子句只是將元素從新排序,而 select 子句則產生從新排序的 Country 對象的序列。

IEnumerable<Country> sortedQuery =
                from country in countries
                orderby country.Area
                select country;

  可使用 select 子句將源數據轉換爲新類型的序列。 這一轉換也稱爲「投影」。

  // Here var is required because the query
            // produces an anonymous type.
            var queryNameAndPop =
                from country in countries
                select new { Name = country.Name, Pop = country.Population };

  group 子句

  使用 group 子句可產生按照指定的鍵組織的組序列, 鍵能夠採用任何數據類型。 例如,下面的查詢建立一個組序列,該序列包含一個或多個 Country 對象,而且它的鍵是 char 值。

var queryCountryGroups =
                from country in countries
                group country by country.Name[0];    //country.name[0] is char type.

  使用「into」進行延續

  能夠在 select 或 group 子句中使用 into 關鍵字來建立用於存儲查詢的臨時標識符。 當您必須在分組或選擇操做以後對查詢執行附加查詢操做時,須要這樣作。

  在下面的示例中,以一千萬人口範圍爲界對 countries 進行分組。 在建立這些組以後,使用附加子句篩選掉某些組,而後按升序對剩下的組進行排序。 若要執行這些附加操做,須要使用由 countryGroup 表示的延續。

// percentileQuery is an IEnumerable<IGrouping<int, Country>>
            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);
            }

 

  • 篩選、排序和鏈接……(where、orderby、join……)

  在 from 開始子句以及 select 或 group 結束子句之間,全部其餘子句(wherejoinorderbyfromlet)都是可選的。 任何可選子句均可以在查詢正文中使用零次或屢次。

  where 子句

  使用 where 子句能夠根據一個或多個謂詞表達式篩選掉源數據中的某些元素。

  如下示例中的 where 子句含有兩個謂詞:

IEnumerable<City> queryCityPop =
                from city in cities
                where city.Population < 200000 && city.Population > 100000
                select city;

  orderby 子句

  使用 orderby 子句能夠按升序或降序對結果進行排序。 您還能夠指定次要排序順序。

  下面的示例使用 Area 屬性對 country 對象執行主要排序, 而後使用 Population 屬性執行次要排序:

 

 IEnumerable<Country> querySortedCountries =
                from country in countries
                orderby country.Area, country.Population descending
                select country;

 

  join 子句

  使用 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 };

  let 子句

  使用 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(new char[] { ' ' })[0]
                select firstName;

            foreach (string s in queryFirstNames)
                Console.Write(s + " ");
            //Output: Svetlana Claire Sven Cesar
  • 查詢表達式中的子查詢

  查詢子句自己可能包含一個查詢表達式,該查詢表達式有時稱爲「子查詢」。

  每一個子查詢都以它本身的 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()
                };

參考

  [1] MSDN,LINQ查詢表達式

  [2] 維基百科,LINQ語言集成查詢

相關文章
相關標籤/搜索