第十二節:Lambda、linq、SQL的相愛相殺(1)


一. 談情懷

   Lambda、Linq、SQL伴隨着我的開發一年又一年,但它們三者並沒有此消彼長,各自占有這一定的比重,起着不可替代的作用。

     相信我們最先接觸的應該就是SQL了,凡是科班出身的人,大學期間都會學習SQL Server數據庫,當然也會學習SQL語言了(順便吐槽一下,學校用SQL Server版本真老,好像是2005,我現在都用2016了),補充一點:主流數據庫像SQL Sever、MySQL、Oracle某些語句是不同的,在后面介紹分頁的時候會有體現。

    (1). SQL:是關系型數據庫標准語言,其特點:簡單,靈活,功能強大。(詳細的概念介紹見  數據庫概述

    后來在工作中接觸到了強大的ORM框架EF,發現了一種寫法  db.Sys_UserInfor.Where(u => u.userAccount == "admin").ToList(); 徹底顛覆了我的三觀,查詢數據庫,竟然可以這么簡單,后來查詢了一下,這個東西叫Lambda

    (2). Lambda:是比匿名方法更簡潔的一種語法,包括 Lambda表達式Lambda語句

  補充Lambad的發展歷史:  

  A. 內置委托: new Func<string, int>(delegate(string str) { return str.Length; }); 

  B. 匿名方法: delegate(string str){return str.Length;}

  C. lambda語句: (string str)=>{return str.Length;}

  D. lambda表達式: (string str)=> str.Length

  E.讓編譯器推斷類型: (str)=> str.Length

  F. 去掉不必要的括弧: str=> str.Length

  注意:Lambda語句 和 Lambda表達式 的區別在於,前者在 =>右邊有一個語句塊(大括號),而后者只有一個表達式(沒有return 和大括號)。Lambda本身無類型,所以不能賦值給 var 變量。編譯時會生成一個靜態方法, 然后再實例化成委托傳遞。

  1. Lambda表達式: list.FindAll(d => d.Id > 2);   又名:點標記。

  2. Lambda語句:list.ForEach(d => { if (d.Id > 2) { Response.Write(d.ToString()); } });

    (3). Linq:是最接近SQL語言的一種查詢表達式,又稱語言集成查詢,它是C# 3.0 時代的產物。

       它與SQL寫法上的本質區別是: linq是以from開頭 select 或group by結尾。

二. 數據准備

 我們准備兩張表 用戶表Sys_UserInfor和用戶登錄記錄表LoginRecords。

   表結構:

     

     

 表數據:

      

     

三. Lambda開篇

1. Where用法

 Where用法相對比較簡單,多個並列條件可以在一個Where中用&&符號鏈接,也可以寫過個Where,最終的結果結果相同

 1        DataDBEntities db = new DataDBEntities();
 2             #region 01-where用法
 3             {
 4                 //1. where用法
 5                 //1.1 查詢賬號為admin的用戶信息
 6                 Console.WriteLine("---------------------------- 1. where用法   ----------------------------------------");
 7                 Console.WriteLine("---------------------------- 1.1 查詢賬號為admin的用戶信息   ----------------------------------------");
 8                 List<Sys_UserInfor> sUserList1 = db.Sys_UserInfor.Where(u => u.userAccount == "admin").ToList();
 9                 foreach (var item in sUserList1)
10                 {
11                     Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3}", item.userName, item.userAccount, item.userAge, item.userSex);
12                 }
13                 //1.2  查詢賬號為中包含admin且性別為男的用戶信息
14                 Console.WriteLine("---------------------------- 1.2  查詢賬號為中包含admin且性別為男的用戶信息   ----------------------------------------");
15                 List<Sys_UserInfor> sUserList2 = db.Sys_UserInfor.Where(u => u.userAccount.Contains("admin") && u.userSex == "").ToList();
16                 foreach (var item in sUserList2)
17                 {
18                     Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3}", item.userName, item.userAccount, item.userAge, item.userSex);
19                 }
20             }
21             #endregion

2. Select用法

  Select中可以查詢所有數據,也可以查詢指定字段。

       當查詢所有數據的時候可以這么寫:var sUserList22 = db.Sys_UserInfor.Where(u => u.userAccount.Contains("admin")).Select(u=>u).ToList();  或者直接可以省略Select部分。

  當查詢部分數據的時候: 可以用匿名類,也可以用實體。

  即使用匿名類的時候,也可以指定列名,不指定的話,默認和數據庫的列名一致。

 1        #region 02-select用法 (匿名類和非匿名類寫法)
 2             {
 3                 //2. select用法 (匿名類和非匿名類寫法)
 4                 //2.1 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (匿名類的寫法,自動生成匿名類名稱)
 5                 Console.WriteLine("---------------------------- 2. select用法 (匿名類和非匿名類寫法)   ----------------------------------------");
 6                 Console.WriteLine("-------------2.1 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (匿名類的寫法)-------------------------");
 7                 var sUserList1 = db.Sys_UserInfor.Where(u => u.userAccount.Contains("admin")).Select(u => new
 8                 {
 9                     u.userName,
10                     u.userAge,
11                     u.userSex
12                 }).ToList();
13                 sUserList1.ForEach(u =>
14                 {
15                     Console.WriteLine("用戶名:{0},用戶年齡:{1},用戶性別:{2}", u.userName, u.userAge, u.userSex);
16                 });
17                 //2.2 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (匿名類的寫法,指定匿名類名稱)
18                 Console.WriteLine("---------2.2 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (匿名類的寫法 指定匿名類名稱)--------");
19                 var sUserList2 = db.Sys_UserInfor.Where(u => u.userAccount.Contains("admin")).Select(u => new
20                 {
21                     Name = u.userName,
22                     Age = u.userAge,
23                     Sex = u.userSex
24                 }).ToList();
25                 sUserList2.ForEach(u =>
26                 {
27                     Console.WriteLine("用戶名:{0},用戶年齡:{1},用戶性別:{2}", u.Name, u.Age, u.Sex);
28                 });
29                 //2.3 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (非匿名類的寫法)
30                 Console.WriteLine("-------------2.3 查詢賬號中包含 admin 的用戶的 姓名、年齡和性別 三條信息 (非匿名類的寫法)-------------------------");
31                 List<newUserInfor> sUserList3 = db.Sys_UserInfor.Where(u => u.userAccount.Contains("admin")).Select(u => new newUserInfor
32                 {
33                     newName = u.userName,
34                     newAge = u.userAge,
35                     newSex = u.userSex
36                 }).ToList();
37                 sUserList3.ForEach(u =>
38                 {
39                     Console.WriteLine("用戶名:{0},用戶年齡:{1},用戶性別:{2}", u.newName, u.newAge, u.newSex);
40                 });
41             }
42             #endregion

3. OrderBy(OrderByDescending、ThenBy、ThenByDescending)用法

  排序的用法在Lambda、Linq和SQL中相差還是很大的,寫法的關鍵字截然不同。

  在Lambda中:升序: OrderBy→ThenBy→ThenBy

         降序: OrderByDescending→ThenByDescending

       先升序后降序再升序: OrderBy→ThenByDescending→ThenBy

 1       #region 03-OrderBy(OrderByDescending、ThenBy、ThenByDescending)用法
 2             {
 3                 //3. OrderBy(OrderByDescending、ThenBy、ThenByDescending)用法  (單條件升降序、多條件綜合排序)
 4                 //3.1 查詢delflag 為1 的所有用戶信息,按照時間升序排列
 5                 Console.WriteLine("------3. OrderBy(OrderByDescending、ThenBy、ThenByDescending)用法  (單條件升降序、多條件綜合排序)-------------");
 6                 Console.WriteLine("--------------------- 3.1 查詢delflag 為1 的所有用戶信息,按照時間升序排列   ------------------------------");
 7                 List<Sys_UserInfor> sUserList1 = db.Sys_UserInfor.Where(u => u.delFlag == 1).OrderBy(u => u.addTime).ToList();
 8                 foreach (var item in sUserList1)
 9                 {
10                     Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3},創建時間:{4}", item.userName, item.userAccount, item.userAge, item.userSex, item.addTime);
11                 }
12                 //3.2 查詢delflag 為1 的所有用戶信息,先按照時間升序排列,再按照年齡降序
13                 Console.WriteLine("---------------3.2 查詢delflag 為1 的所有用戶信息,先按照時間升序排列,再按照年齡降序----------------------");
14                 List<Sys_UserInfor> sUserList2 = db.Sys_UserInfor.Where(u => u.delFlag == 1).OrderBy(u => u.addTime).ThenByDescending(u => u.userAge).ToList();
15                 foreach (var item in sUserList2)
16                 {
17                     Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3},創建時間:{4}", item.userName, item.userAccount, item.userAge, item.userSex, item.addTime);
18                 }
19             }
20             #endregion

 

4. join連接查詢

  這里展示的類似全連接的查詢,在多表查詢,特別是內連接和外鏈接方面明顯不如 Linq和SQL。

 1  #region 04-join連接查詢(作用僅限與此么?)
 2             {
 3                 //4. join連接查詢(匿名類和非匿名類)
 4                 Console.WriteLine("-------------------- 4. join連接查詢(匿名類和非匿名類)------------------------");
 5                 var sUserList = db.Sys_UserInfor;
 6                 var sLoginRecordsList = db.LoginRecords;
 7                 var newList = sUserList.Join(sLoginRecordsList, u => u.id, p => p.userId, (u, p) => new
 8                   {
 9                       UserName = u.userName,
10                       LoginIp = p.loginIp,
11                       LoginCity = p.loginCity,
12                       LoginTime = p.loginTime
13 
14                   }).ToList();
15                 newList.ForEach(a => Console.WriteLine("姓名:{0},登錄IP:{1},登錄城市:{2},登錄時間:{3}", a.UserName, a.LoginIp, a.LoginCity, a.LoginTime));
16 
17                 //非匿名類的情況與上述select中的用法相似
18             } 
19             #endregion

 

5. GroupBy分組(匿名類寫法)

  這里建議使用var類型接收,原類型太難記憶了,記住一點Lambda和Linq可以把分組依據和分組后對應的數據一次性全部拿出來,但是SQL中分組只能查詢分組的依據和使用聚合函數處理其它字段,不能直接查詢非分組依據以外的字段。

 1  #region 05-GroupBy分組(匿名類寫法)
 2             {
 3                 //5. GroupBy分組(需要重點看一下)
 4                 //5.1 根據用戶的性別進行分類,然后將不同性別的用戶信息輸出來
 5                 Console.WriteLine("-------------------- 5. GroupBy分組------------------------");
 6                 Console.WriteLine("-------------------- 5.1 根據用戶的性別進行分類,然后將不同性別的用戶信息輸出來------------------------");
 7                 var sUserListGroup = db.Sys_UserInfor.GroupBy(u => u.userSex).ToList();
 8                 foreach (var group in sUserListGroup)
 9                 {
10                     Console.WriteLine("性別為:{0}", group.Key);    //分組依據的字段內容
11                     foreach (var item in group)
12                     {
13                         Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3}", item.userName, item.userAccount, item.userAge, item.userSex);
14                     }
15                 }
16                 //5.2 根據用戶性別進行分類,然后將不同性別的年齡大於等於21歲的用戶信息輸出來
17                 Console.WriteLine("-------------5.2 根據用戶性別進行分類,然后將不同性別的年齡大於等於21歲的用戶信息輸出來-------------------");
18                 var sUserListGroup2 = db.Sys_UserInfor.Where(u => u.userAge >= 21).GroupBy(u => u.userSex).ToList();
19                 foreach (var group in sUserListGroup2)
20                 {
21                     Console.WriteLine("性別為:{0}", group.Key);    //分組依據的字段內容
22                     foreach (var item in group)
23                     {
24                         Console.WriteLine("用戶名:{0},用戶賬號:{1},用戶年齡:{2},用戶性別:{3}", item.userName, item.userAccount, item.userAge, item.userSex);
25                     }
26                 }
27             } 
28             #endregion

 

6. Skip和Take用法

  這里結合Skip和Take寫分頁,太方便了,分頁公式:   

    data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
 補充MySQL數據中特有的分頁,也很方便,分頁公式:SELECT * FROM 表名 LIMIT (pageIndex-1)*pageSize,pageSize .
 1   #region 06-Skip和Take用法
 2             {
 3                 //6. Skip和Take 分頁用法
 4                 //skip表示跳過多少條,Take表示取多少條
 5                 //6.1 根據時間降序排列,取第2和第3條數據(即先排序,然后跨過1條,取2條數據)
 6                 Console.WriteLine("--------------------6. Skip和Take 分頁用法------------------------");
 7                 Console.WriteLine("---------6.1 根據時間降序排列,取第2和第3條數據(即先排序,然后跨過1條,取2條數據)---------");
 8                 var sUserList = db.Sys_UserInfor.OrderByDescending(u => u.addTime).Skip(1).Take(2).ToList();
 9                 sUserList.ForEach(u =>
10                 {
11                     Console.WriteLine("用戶名:{0},用戶年齡:{1},用戶性別:{2},創建時間:{3}", u.userName, u.userAge, u.userSex, u.addTime);
12                 });
13 
14                 // 6.2 分頁公式
15                 // 每頁兩條數據,根據時間降序,取第三頁的所有數據
16                 Console.WriteLine("---------6.2 每頁兩條數據,根據時間降序,取第三頁的所有數據---------");
17                 var sUserList2 = GetDataByIndex(db.Sys_UserInfor.OrderByDescending(u => u.addTime).ToList(), 3, 2);
18                 sUserList2.ForEach(u =>
19                 {
20                     Console.WriteLine("用戶名:{0},用戶年齡:{1},用戶性別:{2},創建時間:{3}", u.userName, u.userAge, u.userSex, u.addTime);
21                 });
22             } 
23             #endregion
1     #region 分頁公式
2         static List<Sys_UserInfor> GetDataByIndex(List<Sys_UserInfor> data, int pageIndex, int pageSize)
3         {
4             return data.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
5         } 
6         #endregion

 

7. GroupJoin外連接查詢(相當於left Join)

 1  #region 06-GroupJoin外連接查詢(相當於left Join)
 2                 {
 3                     Console.WriteLine("-------------------- 06-GroupJoin多表關聯分組------------------------");
 4                     Console.WriteLine("--------------------根據性別分組,輸出相同性別的用戶和登錄城市 ------------------------");
 5                     var list = db.Sys_UserInfor.GroupJoin(db.LoginRecord2, (Sys_UserInfor a) => a.id, (LoginRecord2 b) => b.userId, (m,n) => new
 6                     {
 7                         m.userName,
 8                         n
 9                     }).ToList();
10 
11                     foreach (var item in list)
12                     {
13                         var userName = item.userName;
14                         foreach (var cItem in item.n.ToList())
15                         {
16                             Console.WriteLine("用戶名為{0}的用戶的登錄城市是:{1},登錄時間是:{2}", userName, cItem.loginCity,cItem.loginTime);
17                         }
18                     }
19                 }
20                 #endregion

 

 

 

 

 
 
 
 

 

     


免責聲明!

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



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