Linq學習之旅——LINQ查詢表達式


目錄

1. 概述

2. from子句

3. where子句

4. select子句

5. group子句

6. into子句

7. 排序子句

8. let子句

9. join子句

10. 小結

1. 概述

    LINQ的全稱是Language Integrated Query,中文譯成“語言集成查詢”。LINQ作為一種查詢技術,首先要解決數據源的封裝,大致使用了三大組件來實現這個封裝,分別是LINQ to Object、LINQ to ADO.NET、LINQ to XML。它們和.NET語言的關系如下:

 

    要使用LINQ來編程,首先要學習使用LINQ的子句以及由查詢語法構成的查詢表達式。C#3.0和VB9開始將這種查詢語法引入到了編程語言,並新增了一系列的關鍵字。但對於CLR本身來說,它並不了解查詢語法,它能理解的是由編程語言的編譯器將這種查詢語法轉換成的方法。這些方法叫“標准查詢運算符”,它們具有類似這樣的名稱——Where、Select、GroupBy、Join。下面就以C#為例,從編程語言的層面來具體介紹這些查詢語法(注意VB9也支持這種查詢語法)。

    LINQ的查詢由3基本部分組成:獲取數據源,創建查詢,執行查詢

            // 1,獲取數據源
            List<int> numbers = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

            // 2,創建查詢
            var numQuery = from num in numbers
                           where num % 2 == 0
                           select num;

            // 3,執行查詢
            foreach (var num in numQuery)
            {
                Console.WriteLine("{0,1}", num);
            }

下圖顯示了完整的查詢操作。在 LINQ 中,查詢的執行與查詢本身截然不同;換句話說,如果只是創建查詢變量,則不會檢索任何數據。

如上例所示,Linq的數據源要求必須實現IEnumerable或IEnumerable<T>接口,數組隱式支持這個接口。numQuery叫做查詢變量,它存儲了一個查詢表達式。注意,聲明查詢變量並不會執行查詢,真正的執行查詢延遲到了foreach語句中。

2. from子句

    創建一個LINQ表達式必須要以from子句開頭。

2.1 單個from子句

            string[] values = { "中國", "日本", "美國", "菲律賓", "越南" };

            //查詢包含“國”的字符串
            var valueQuery = from v in values
                             where v.IndexOf("") > 0
                             select v;

            foreach (var v in valueQuery)
            {
                Console.WriteLine("{0,1}", v);
            }

在這個LINQ表達式的from子句中,v叫做范圍變量,values是數據源。v的作用域存在於當前的LINQ表達式,表達式以外不能訪問這個變量。where用來篩選元素,select用於輸出元素。這里的范圍變量v,和foreach語句中得隱式變量v都可以由編譯器推斷出其類型。
運行的結果如下:

中國
美國

使用LINQ查詢List<T>集合

        public class CustomerInfo
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public string Tel { get; set; }
        }
        private void formExpDemo2()
        {
            //這里用了,對象和集合初始化器
            List<CustomerInfo> customers = new List<CustomerInfo> { 
                                           new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                           new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                           new CustomerInfo{ Name="諸葛菲菲", Age=23, Tel ="1380524****"}
                                           };
            //查詢年齡大於20的客戶,注意這里的范圍變量用了顯示類型CustomerInfo
            var query = from CustomerInfo ci in customers
                        where ci.Age > 20
                        select ci;
            
            foreach (CustomerInfo ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }
        }

結果:

姓名:歐陽曉曉 年齡:35 電話:1330708****
姓名:諸葛菲菲 年齡:23 電話:1380524****

2.2 復合from子句

    在查詢數據源中,元素的屬性是一個集合時,可以使用復合from子句對這個屬性集合查詢。比如,一個客戶,可能有多個電話。

        public class CustomerInfo
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public List<string> TelTable { get; set; }
        }
        private void formExpDemo()
        {
            List<CustomerInfo> customers = new List<CustomerInfo> { 
                                           new CustomerInfo{ Name="歐陽曉曉", Age=35, TelTable=new List<string>{"1330708****","1330709****"}},
                                           new CustomerInfo{ Name="上官飄飄", Age=17, TelTable=new List<string>{"1592842****","1592843****"}},
                                           new CustomerInfo{ Name="諸葛菲菲", Age=23, TelTable=new List<string>{"1380524****","1380525****"}}
                                           };
            //查詢包含電話號碼1592842****的客戶
            var query = from CustomerInfo ci in customers
                        from tel in ci.TelTable
                        where tel.IndexOf("1592842****") > -1
                        select ci;

            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1}", ci.Name, ci.Age);
                foreach (var tel in ci.TelTable)
                {
                    Console.WriteLine("          電話:{0}", tel);
                }
            }
        }

結果:

姓名:上官飄飄 年齡:17
          電話:1592842****
          電話:1592843****

2.3 多個from子句

   多個from子句查詢和復合from子句從字面上看似乎一樣,其實是不同的操作。復合from子句查詢的是單個數據源中的子元素的集合,而多個from子句,是載入多個數據源進行查詢。

        private void formExpDemo()
        {
            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="諸葛菲菲", Age=23, Tel ="1380524****"}
                                                   };
            List<CustomerInfo> clist2 = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="令狐沖", Age=25, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="東方不敗", Age=35, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="任盈盈", Age=23, Tel ="1380524****"}
                                                   };

            //在clist中查找Age大於20的客戶,
            //在clist2中查找Age小於30的客戶
            var query = from customer in clist
                        where customer.Age > 20
                        from customer2 in clist2
                        where customer2.Age < 30
                        select new { customer, customer2 };

            foreach (var ci in query)
            {
                Console.WriteLine("{0} {1}", ci.customer.Name,ci.customer2.Name);
            }
        }

在select語句中,我們用了匿名類型來存儲篩選出的元素,這樣得到的完全是一個交叉聯接表,有點類似於SQL中的笛卡爾乘積。

輸出的結果:

歐陽曉曉 令狐沖
歐陽曉曉 任盈盈
諸葛菲菲 令狐沖
諸葛菲菲 任盈盈

3. where子句

     where子句的作用就是篩選元素,除了開始和結束位置,where子句幾乎可以出現在LINQ表達式的任意位置。一個LINQ表達式中可以有where子句,也可以沒有;可以有一個,可以有多個;多個where子句之間的關系相當於邏輯“與”,每個where子句可以包含1個或多個邏輯表達式,這些條件成為“謂詞”,多個謂詞之間用布爾運算符隔開,比如邏輯“與”用&&,邏輯“或”用||,而不是用SQL中的AND或OR。

3.1 常見的where子句查詢

            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="令狐沖", Age=23, Tel ="1380524****"}
                                                   };

            //查詢名字是3個字或者姓“令”的,但年齡大於20的客戶
            var query = from customer in clist
                        where (customer.Name.Length == 3 || customer.Name.Substring(0, 1) == "")
                        && customer.Age > 20
                        select customer;

            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }

結果:

姓名:令狐沖 年齡:23 電話:1380524****

3.2 在where子句中使用自定義函數

        private void whereExpDemo()
        {
            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="令狐沖", Age=23, Tel ="1380524****"}
                                                   };

            //查詢名字是3個字並且姓“令”的客戶
            var query = from customer in clist
                        where (customer.Name.Length == 3 && CheckName(customer.Name))
                        select customer;

            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }
        }
        private bool CheckName(string name)
        {
            if (name.Substring(0, 1) == "")
                return true;
            else
                return false;
        }

結果:

姓名:令狐沖 年齡:23 電話:1380524****

 3.3 動態謂詞的篩選

    上面的幾個例子都是給定了查詢謂詞然后進行查詢,有時候謂詞的數量可能並不固定,是隨情況變化的。例如:一組名字可能是運行時動態指定的。

            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="令狐沖", Age=23, Tel ="1380524****"}
                                                   };

            //定義動態的謂詞數組,這個數組應該由實際運行環境生成
            string[] names = { "令狐沖", "任盈盈", "楊過", "小龍女", "歐陽曉曉" };

            //查詢在給定謂詞數組里存在的客戶
            var query = from customer in clist
                        where names.Contains(customer.Name)
                        select customer;

            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }

結果:

姓名:歐陽曉曉 年齡:35 電話:1330708****
姓名:令狐沖 年齡:23 電話:1380524****

4. select子句

 LINQ表達式的結果是使用select子句獲得的。select子句可以對數據進行轉換,這個過程稱為“投影”。select子句產生的類容,取決於前面的所有子句及其自身表達式執行后的結果。

4.1 輸出查詢結果

最簡單的select就是直接輸出from子句建立的那個范圍變量:

            var query = from customer in clist
                        where names.Contains(customer.Name)
                        select customer;

也可以輸出范圍變量類型中得某個屬性:

                        select customer.Name;

或者修改一下再輸出:

select customer.Name.Replace("gg","mm");

或者干脆使用一個自定義的函數,把范圍變量傳進去,輸出處理后的結果:

select MyFunction(customer.Name);

4.2 對查詢結果進行投影

        public class MyCustomerInfo
        {
            public string Name { get; set; }
            public string Tel { get; set; }
        }
        private void whereExpDemo()
        {
            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="令狐沖", Age=23, Tel ="1380524****"}
                                                   };

            //定義動態的謂詞數組,這個數組應該由實際運行環境生成
            string[] names = { "令狐沖", "任盈盈", "楊過", "小龍女", "歐陽曉曉" };

            //查詢在給定謂詞數組里存在的客戶
            var query = from customer in clist
                        where customer.Age < 30
                        select new MyCustomerInfo { Name = customer.Name, Tel = customer.Tel };

            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 電話:{1} 類型{2}", ci.Name, ci.Tel,ci.GetType().FullName);
            }
        }

上例中,在select子句中用對象初始化器生成了新的數據類型,從而進行了數據轉換,使元素變成了MyCustomerInfo類型。

結果:

姓名:上官飄飄 電話:1592842**** 類型LinqDemo.Form1+MyCustomerInfo
姓名:令狐沖 電話:1380524**** 類型LinqDemo.Form1+MyCustomerInfo

5. group子句

    按照語法的規定,LINQ表達式必須以from子句開頭,以select或group子句結束,所以除了使用select子句外,也可以使用guoup子句來返回元素分組后的結果。group子句返回的是一個IGrouping<TKey,TElement>泛型接口的對象集合,下面先了解下這個接口。

5.1 IGrouping<TKey,TElement>泛型接口

    這個接口表示具有公共鍵的對象集合,它的原型如下:

public interface IGrouping<TKey, TElement> : IEnumerable<TElement>, 
    IEnumerable

TKey是鍵的對象類型,在用於group子句的時候,數據類型會有編譯器推斷出來,它一般用於存儲分組的鍵值;TElement是指的對象類型,用於存儲分組的結果,變量基於這個接口的類型就是遍歷這個值。

5.2 分組查詢

    分組查詢對於關系型數據庫是非常常見的一種操作,但在沒有LINQ之前,對內存的對象進行分組卻是一件非常麻煩的事情。現在,在LINQ表達式中只需要使用group子句就可以輕松完成對內存對象的分組。

            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="歐陽錦鵬", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官無忌", Age=23, Tel ="1380524****"}
                                                   };

            //按照名字的前2個字進行分組
            var query = from customer in clist
                        group customer by customer.Name.Substring(0, 2);

            foreach (IGrouping<string,CustomerInfo> group in query)
            {
                Console.WriteLine("分組鍵:{0}",group.Key);
                foreach (var ci in group)
                {
                    Console.WriteLine("姓名:{0} 電話:{1}", ci.Name, ci.Tel);
                }
                Console.WriteLine("***************************************");
            }

上例代碼,按照form子句建立的范圍變量customer的Name屬性的前兩個字作為鍵值進行分組。所以TKey的類型是一個字符串類型。

輸出結果:

分組鍵:歐陽
姓名:歐陽曉曉 電話:1330708****
姓名:歐陽錦鵬 電話:1330708****
***************************************
分組鍵:上官
姓名:上官飄飄 電話:1592842****
姓名:上官無忌 電話:1380524****
***************************************

再看一個分組的例子:

            //按照年齡是否大於20分組
            var query = from customer in clist
                        group customer by customer.Age > 20;

            foreach (var group in query)
            {
                Console.WriteLine("分組鍵:{0}",group.Key);
                foreach (var ci in group)
                {
                    Console.WriteLine("姓名:{0} 電話:{1}", ci.Name, ci.Tel);
                }
                Console.WriteLine("***************************************");
            }

group子句用了一個布爾表達式,所以IGrouping<TKey,TElement>的TKey變成了一個bool型。並且循環遍歷的時候可以用var代替IGrouping的聲明:

foreach (var group in query)

結果如下:

分組鍵:True
姓名:歐陽曉曉 電話:1330708****
姓名:歐陽錦鵬 電話:1330708****
姓名:上官無忌 電話:1380524****
***************************************
分組鍵:False
姓名:上官飄飄 電話:1592842****
***************************************

6. into子句

    into子句作為一個臨時標識符,用於select,group,join子句中。

  List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="歐陽錦鵬", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官無忌", Age=23, Tel ="1380524****"}
                                                   };

            //按照名字的前兩個字進行分組,再用分組Key進行排序
            var query = from customer in clist
                        group customer by customer.Name.Substring(0, 2) into gpcustomer
                        orderby gpcustomer.Key descending
                        select gpcustomer;
            Console.WriteLine("into 用於group子句");
            foreach (var group in query)
            {
                Console.WriteLine("分組鍵:{0}", group.Key);
                foreach (var ci in group)
                {
                    Console.WriteLine("姓名:{0} 電話:{1}", ci.Name, ci.Tel);
                }
                Console.WriteLine("***************************************");
            }

            var query2 = from customer in clist
                         select new { NewName = customer.Name, NewAge = customer.Age } into newCustomer
                         orderby newCustomer.NewAge
                         select newCustomer;

            Console.WriteLine("into 用於select子句");
            foreach (var ci in query2)
            {
                Console.WriteLine("{0} 年齡:{1}", ci.NewName, ci.NewAge);
            }

    into子句提供了一個臨時標識符,它存儲了into子句前面的查詢內容,使它后面的子句可以方便的使用,對其進行再次查詢,投影等操作。
執行結果:

into 用於group子句
分組鍵:上官
姓名:上官飄飄 電話:1592842****
姓名:上官無忌 電話:1380524****
***************************************
分組鍵:歐陽
姓名:歐陽曉曉 電話:1330708****
姓名:歐陽錦鵬 電話:1330708****
***************************************
into 用於select子句
上官飄飄 年齡:17
上官無忌 年齡:23
歐陽曉曉 年齡:35
歐陽錦鵬 年齡:35

7. 排序子句

    LINQ可以按元素的一個或多個屬性對元素進行排序。LINQ表達式的排序方式分為OrderBy、OrderByDescending、ThenBy、ThenByDescending這四種。

7.1 OrderBy和OrderByDescending

    OrderBy用於按元素的值進行升序,語法:

orderby 用於排序的元素的表達式

OrderByDescending用於按元素的值進行降序,語法:

orderby 用於排序的元素的表達式 descending
            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="歐陽錦鵬", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官無忌", Age=23, Tel ="1380524****"}
                                                   };

            //按照年齡升序
            var query = from customer in clist
                        orderby customer.Age
                        select customer;
            Console.WriteLine("按年齡升序排列");
            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }
            //按照年齡降序
            var query2 = from customer in clist
                        orderby customer.Age descending
                        select customer;
            Console.WriteLine("\n按年齡降序排列");
            foreach (var ci in query2)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }

運行結果:

按年齡升序排列
姓名:上官飄飄 年齡:17 電話:1592842****
姓名:上官無忌 年齡:23 電話:1380524****
姓名:歐陽曉曉 年齡:35 電話:1330708****
姓名:歐陽錦鵬 年齡:35 電話:1330708****

按年齡降序排列
姓名:歐陽曉曉 年齡:35 電話:1330708****
姓名:歐陽錦鵬 年齡:35 電話:1330708****
姓名:上官無忌 年齡:23 電話:1380524****
姓名:上官飄飄 年齡:17 電話:1592842****

7.2 ThenBy和ThenByDescending

    ThenBy和ThenByDescending用於對元素進行次要排序。基本語法:

orderby 用於排序的元素表達式,用於排序的元素表達式
orderby 用於排序的元素表達式,用於排序的元素表達式 descending
            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="郭靖", Age=17, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="黃蓉", Age=17, Tel ="1300524****"}
                                                   };

            //按照年齡升序,再按名字的字數次要排序
            var query = from customer in clist
                        orderby customer.Age,customer.Name.Length
                        select customer;
            Console.WriteLine("按年齡排列,按名字字數進行次要排序");
            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }
            //按照年齡升序,再按名字的字數降序次要排序
            var query2 = from customer in clist
                        orderby customer.Age, customer.Name.Length descending
                        select customer;
            Console.WriteLine("\n按年齡排列,按名字字數進行降序次要排序");
            foreach (var ci in query2)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }
            //按照年齡升序,再按名字的字數降序要排序,在按電話號碼進行第三條件排序
            var query3 = from customer in clist
                         orderby customer.Age, customer.Name.Length,customer.Tel
                         select customer;
            Console.WriteLine("\n按年齡,名字字數,電話號碼排序");
            foreach (var ci in query3)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }

執行結果:

按年齡排列,按名字字數進行次要排序
姓名:郭靖 年齡:17 電話:1330708****
姓名:黃蓉 年齡:17 電話:1300524****
姓名:上官飄飄 年齡:17 電話:1592842****
姓名:歐陽曉曉 年齡:35 電話:1330708****

按年齡排列,按名字字數進行降序次要排序
姓名:上官飄飄 年齡:17 電話:1592842****
姓名:郭靖 年齡:17 電話:1330708****
姓名:黃蓉 年齡:17 電話:1300524****
姓名:歐陽曉曉 年齡:35 電話:1330708****

按年齡,名字字數,電話號碼排序
姓名:黃蓉 年齡:17 電話:1300524****
姓名:郭靖 年齡:17 電話:1330708****
姓名:上官飄飄 年齡:17 電話:1592842****
姓名:歐陽曉曉 年齡:35 電話:1330708****

8. let子句

    let子句用於在LINQ表達式中存儲子表達式的計算結果。let子句創建一個范圍變量來存儲結果,變量被創建后,不能修改或把其他表達式的結果重新賦值給它。此范圍變量可以再后續的LINQ子句中使用。 

            List<CustomerInfo> clist = new List<CustomerInfo> { 
                                                   new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
                                                   new CustomerInfo{ Name="郭靖", Age=17, Tel ="1330708****"},
                                                   new CustomerInfo{ Name="黃蓉", Age=17, Tel ="1300524****"}
                                                   };

            //姓“郭”或“黃”的客戶
            var query = from customer in clist
                        let g = customer.Name.Substring(0,1)
                        where g == "" || g == ""
                        select customer;
            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} 電話:{2}", ci.Name, ci.Age, ci.Tel);
            }         
          

使用let 建立了個范圍變量,這個范圍變量在后續的where子句中使用,如果不使用let子句,where子句的表達式將寫成這樣:

where customer.Name.Substring(0, 1) == "" || customer.Name.Substring(0, 1) == ""

執行結果:

姓名:郭靖 年齡:17 電話:1330708****
姓名:黃蓉 年齡:17 電話:1300524****

9. join子句

    如果一個數據源中元素的某個屬性可以跟另一個數據源中元素的屬性進行相等比較,那么這兩個數據源可以用join子句進行關聯。jion子句用equals關鍵字進行比較,而不是常見的==。

      List<CustomerInfo> clist = new List<CustomerInfo> 
            { 
               new CustomerInfo{ Name="歐陽曉曉", Age=35, Tel ="1330708****"},
               new CustomerInfo{ Name="上官飄飄", Age=17, Tel ="1592842****"},
               new CustomerInfo{ Name="郭靖", Age=17, Tel ="1330708****"},
               new CustomerInfo{ Name="黃蓉", Age=17, Tel ="1300524****"}
            };

            List<CustomerTitle> titleList = new List<CustomerTitle> 
            { 
               new CustomerTitle{ Name="歐陽曉曉", Title="歌手"},
               new CustomerTitle{ Name="郭靖", Title="大俠"},
               new CustomerTitle{ Name="郭靖", Title="洪七公徒弟"},
               new CustomerTitle{ Name="黃蓉", Title="才女"},
               new CustomerTitle{ Name="黃蓉", Title="丐幫幫主"}
            };

            //根據姓名進行內部聯接
            Console.WriteLine("內部聯接");
            var query = from customer in clist
                        join title in titleList
                        on customer.Name equals title.Name
                        select new { Name = customer.Name, Age = customer.Age, Title = title.Title };
            foreach (var ci in query)
            {
                Console.WriteLine("姓名:{0} 年齡:{1} {2}", ci.Name, ci.Age, ci.Title);
            }
            //根據姓名進行分組聯接
            Console.WriteLine("\n根據姓名進行分組聯接");
            var query2 = from customer in clist
                         join title in titleList
                         on customer.Name equals title.Name into tgroup
                         select new { Name = customer.Name, Titles = tgroup };
            foreach (var g in query2)
            {
                Console.WriteLine(g.Name);
                foreach (var g2 in g.Titles)
                {
                    Console.WriteLine("   {0}", g2.Title);
                }
            }
            //根據姓名進行 左外部聯接
            Console.WriteLine("\n左外部聯接");
            var query3 = from customer in clist
                         join title in titleList
                         on customer.Name equals title.Name into tgroup
                         from subTitle in tgroup.DefaultIfEmpty()
                         select new { Name = customer.Name, Title = (subTitle == null ? "空缺" : subTitle.Title) };
            foreach (var ci in query3)
            {
                Console.WriteLine("姓名:{0} {1} ", ci.Name, ci.Title);
            }

要仔細理解上例的,內聯接,分組聯接,以及左聯接。

執行結果:

內部聯接
姓名:歐陽曉曉 年齡:35 歌手
姓名:郭靖 年齡:17 大俠
姓名:郭靖 年齡:17 洪七公徒弟
姓名:黃蓉 年齡:17 才女
姓名:黃蓉 年齡:17 丐幫幫主

根據姓名進行分組聯接
歐陽曉曉
   歌手
上官飄飄
郭靖
   大俠
   洪七公徒弟
黃蓉
   才女
   丐幫幫主

左外部聯接
姓名:歐陽曉曉 歌手 
姓名:上官飄飄 空缺 
姓名:郭靖 大俠 
姓名:郭靖 洪七公徒弟 
姓名:黃蓉 才女 
姓名:黃蓉 丐幫幫主 

10 小結

    本文講述了LINQ表達式的from子句、where子句、select子句、group子句、into子句、排序子句、let子句、join子句等基本子句。這些子句只是LINQ標准查詢符擴展方法的一部分。下一步學習LINQ to Objects的時候,會進一步學習其他的標准查詢符。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM