APS.NET MVC + EF (01)---Linq和Lambda表达式
APS.NET MVC + EF (01)---Linq和Lambda表達(dá)式
1.1 Linq介紹
LINQ全稱 Language Integrated Query(語言集成查詢)。為我們提供一種統(tǒng)一的方式來查詢和操作各種數(shù)據(jù)。
? ?
- LINQ to Object:是針對實現(xiàn)了IEnumerable<T>的對象的LINQ;
- LINQ to SQL:是針對關(guān)系數(shù)據(jù)庫的LINQ;
- LINQ to XML:是針對XML文檔的LINQ。
? ?
LINQ除了提供一個統(tǒng)一的API來操作各種數(shù)據(jù),并且為我們提供了編譯時類型檢查和動態(tài)創(chuàng)建查詢表達(dá)式的能力。
? ?
LINQ查詢時有兩種語法可供選擇:查詢表達(dá)式語法(Query Expression)和方法語法(Fluent Syntax)。這兩種方法是互補(bǔ)的。
? ?
1.1.1 查詢表達(dá)式語法
基本語法:
| from 變量 in 數(shù)據(jù)源對象 [where 條件] [group 變量 by 表達(dá)式 into 臨時標(biāo)識符] [orderby 表達(dá)式] select 選擇列 |
示例1:
| static void Main(string[] args) { int[] nums = { 10, 15, 20, 25, 30 }; // 從數(shù)組中查詢所有偶數(shù) var result = from n in nums where n % 2 == 0 select n; // 輸出查詢結(jié)果 foreach(int num in result) { Console.WriteLine(num); } } |
說明:
1、查詢表達(dá)式語法與SQL(結(jié)構(gòu)查詢語言)語法相同。
2、查詢語法必須以from子句開頭,可以以Select或GroupBy子句結(jié)束?。
3、使用各種其他操作,如過濾,連接,分組,排序運(yùn)算符以構(gòu)造所需的結(jié)果。
4、隱式類型變量 - var可以用于保存LINQ查詢的結(jié)果。
? ?
1.1.2 方法語法
方法語法(也稱為流利語法)主要利用System.Linq.Enumerable類中定義的擴(kuò)展方法和Lambda表達(dá)式方式進(jìn)行查詢。
例如示例1中的查詢可以由以下方式代替,運(yùn)行結(jié)果一致。
| var result = nums.Where(n => n % 2 == 0); |
? ?
關(guān)于Lambda表達(dá)式的語法,我們在后面的內(nèi)容中進(jìn)行詳細(xì)講解。
? ?
1.1.3 查詢表達(dá)式語法VS方法語法
查詢表達(dá)式語法與方法語法存在著緊密的關(guān)系
1、CLR本身并不理解查詢表達(dá)式語法,它只理解方法語法。
2、編譯器負(fù)責(zé)在編譯時將查詢表達(dá)式語法翻譯為方法語法。
3、大部分方法語法都有對應(yīng)的查詢表達(dá)式語法形式:如Select()對應(yīng)select、OrderBy()對應(yīng)orderby
4、部分查詢方法目前在C#中還沒有對應(yīng)的查詢語句:如Count()和Max()
1.2 Linq之查詢語法
1.2.1 排序
用where子句找到感興趣的數(shù)據(jù)后,Linq還可以方便的對得到的數(shù)據(jù)執(zhí)行進(jìn)一步處理,例如,給結(jié)果重新排序。下面的示例將以字母順序給上一個查詢的結(jié)果排序
示例2
| static void Main(string[] args) { string[] names = { "alonso", "zheng", "smith", "jones", "smythe", "small", "Ruiz", "Hsieh", "Jorgenson", "Ilyich", "singh" }; var result = from n in names where n.StartsWith("s") orderby n select n; Console.WriteLine("以s開頭的名字為:"); foreach (var item in result) { Console.WriteLine(item); } } |
示例說明:
- 這個程序與示例1幾乎相同,只是在查詢子句中增加了一行代碼:
orderby n
即實現(xiàn)了對結(jié)果的排序功能。與where子句一樣,orderby子句是可選的。
- Orderby子句默認(rèn)為升序,但可以添加descending關(guān)鍵字,指定降序排列。如:
orderby n descending;
- 可以按照任意表達(dá)式進(jìn)行排序,而無需重新編寫查詢。例如,要按照姓名中的最后一個字母順序排序,只需添加如下子句:
orderby n.Substring(n.Length-1);
? ?
1.2.2 合計運(yùn)算符
| 運(yùn)算符 | 說明 |
| Count() | 結(jié)果的個數(shù) |
| Min() | 結(jié)果中的最小值 |
| Max() | 結(jié)果中的最大值 |
| Average() | 數(shù)字結(jié)果的平均值 |
| Sum() | 所有數(shù)字結(jié)果的和 |
示例3
| class Program { static void Main(string[] args) { int[] numbers = CreateNumbers(12345); var result = from n in numbers where n > 1000 select n; Console.WriteLine("大于1000的個數(shù)為:" + result.Count()); Console.WriteLine("大于1000的最大數(shù)為:" + result.Max()); Console.WriteLine("大于1000的最小數(shù)為:" + result.Min()); Console.WriteLine("大于1000的平均數(shù)為:" + result.Average()); Console.WriteLine("大于1000的數(shù)的和為:" + result.Sum(n=>(long)n)); } ? ? private static int[] CreateNumbers(int count) { Random rand = new Random(0); int[] result = new int[count]; for (int i = 0; i < count; i++) { result[i] = rand.Next(); } return result; } } |
示例說明:
示例3中的Sum()方法傳入了一個Lambda表達(dá)式n=>(long)n,以獲得所有數(shù)字的和。這是Sum()方法的一個重載。由于和的結(jié)果太大,若個只是用Sum()會產(chǎn)生溢出。
? ?
1.2.3 查詢復(fù)雜對象
示例4
| // Student類 class Student { public int ID { get; set; } public string Name { get; set; } public string Sex { get; set; } public int Age{ get; set; } public int Class { get; set; } ? ? public override string ToString() { return "ID:" + ID + "\tName:" + Name + "\tSex:" + Sex + "\tAge:" + Age + "\tClass:" + Class; } } //main 方法 static void Main(string[] args) { List<Student> list = new List<Student>{ new Student{ID=1,Name="zhangsan",Sex="男", Age=18,Class=50}, new Student{ID=2,Name="lisi",Sex="男", Age=18,Class=50}, new Student{ID=3,Name="wuangwu",Sex="男", Age=20,Class=51}, new Student{ID=4,Name="zhaoliu",Sex="男", Age=20,Class=52}, new Student{ID=5,Name="zhouqi",Sex="女", Age=21,Class=52}, new Student{ID=6,Name="wangba",Sex="女", Age=20,Class=52} }; var result = from stu in list where stu.Age == 18 select stu; Console.WriteLine("年齡為18的學(xué)員為:"); foreach (var stu in result) { Console.WriteLine(stu); } } |
? ?
1.2.4 投射:在查詢中創(chuàng)建新對象
投射是在Linq查詢中從其它數(shù)據(jù)類型中創(chuàng)建新數(shù)據(jù)類型的技術(shù)術(shù)語。Select關(guān)鍵字是投射運(yùn)算符。
如Sql數(shù)據(jù)查詢語言,select用來從數(shù)據(jù)表中選擇適當(dāng)?shù)淖侄?#xff0c;在Linq中select與其類似。例如將示例4中的代碼改為如下:
| var result=from stu in list where stu.Age=18 select stu.Name; |
甚至可以通過給select添加表達(dá)式,來轉(zhuǎn)換查詢中的數(shù)據(jù)。如:
select stu.Name.ToUpper();
但是與sql不同,Linq不允許在select子句中有多個字段,即select stu.Name,stu.Age這樣的形式將產(chǎn)生一個錯誤。如果要實現(xiàn)上述情況,需要在select子句中創(chuàng)建一個新對象,來保存查詢的結(jié)果,如示例5所示。
示例5
| //修改示例4Main方法 var result = from stu in list where stu.Age == 18 select new (stu.Name,stu.Age); Console.WriteLine("年齡為18的學(xué)員為:"); foreach (var stu in result) { Console.WriteLine(stu); } ?? |
? ?
1.2.5 多級排序
處理了帶多個屬性的對象后,要考慮按多種方式進(jìn)行排序的問題了,例如我們先按照班級排序,在按照年齡排序。代碼如下:
var result=from stu in list orderby stu.Class,stu.Age select stu;
還可以給字段添加Descending關(guān)鍵字。如
orderby stu.Class,stu.Age.deseending;
1.2.6 分組查詢
在Linq中還可以實現(xiàn)像Sql中的Group by語句一樣的分組統(tǒng)計功能。
示例6
| var result=from stu in list group stu by stu.Class into student select new {Class=student.Key,Count=student.Count()}; ? ? var orderresult=from student in result orderby student.Count descending select student; |
在分組查詢中的數(shù)據(jù)通過一個鍵(key)字段來分組,每個組中的所有程序都共享這個字段值,在此例中鍵字段是Class:
group stu by stu.Class
要計算每個組的數(shù)量,應(yīng)該生成一個新的結(jié)果集student(可自定義):
group stu by stu.Class into student
1.2.7 Join查詢
Join可以用一個查詢搜索兩個列表中相關(guān)的數(shù)據(jù),用關(guān)鍵字段把結(jié)果連接起來。類似于SQL中join(內(nèi)連接)操作。如:
| var result = from stu in list join scr in Scores on stu.ID equals scr.ID select new { stu.ID, stu.Name, scr.score }; ? ? foreach (var ss in result) { Console.WriteLine(ss); } |
? ?
1.3 Linq之方法語法
1.3.1 Lambda表達(dá)式
Lambda表達(dá)式用來實現(xiàn)一個匿名方法,其語法為:
(參數(shù)列表)=> 語句或語句塊
?
這是一個簡單的Lambda表達(dá)式: (item)=>item<1000;
運(yùn)算符 "=>"稱為Lambda表達(dá)式。這個表達(dá)式定義了一個方法,其參數(shù)是item,如果item小于1000,該方法就返回ture,否則返回false。該方法是一個沒有名稱的匿名方法。
?
item=>item<1000;
(ints,item)=>ints.Contains(item);
( ) =>Console.WriteLine("這是一個不帶參數(shù)的Lambda表達(dá)式");
(ints, item) => {
Console.WriteLine("這是包含多條語句的Lambda表達(dá)式");
return ints.Contains(item);
};
當(dāng)需要指定Lambda表達(dá)式返回結(jié)果的類型時,可以使用Func<T,TResult>委托。如下所示:
Func<int[], bool> isContains= p=> p.Equals(10);
int[] ints= { 5 ,2 ,0, 66, 32, 7};
bool result=isContains(ints);
? ?
1.3.2 在Linq中使用Lambda表達(dá)式
回顧示例2中的代碼:
var result = from n in names where n.StartsWith("s") select n;
我們可以用方法語法來實現(xiàn):
var result = names.Where(n => n.StartsWith("s"));
我們發(fā)現(xiàn),用法方法查詢語法更加簡潔。
上面代碼中Where()方法用來篩選,返回符合條件的子集。
對上面的查詢結(jié)果排序可以使用如下語句。
var result = names.OrderBy(n => n).Where(n => n.StartsWith("s"));
或者
var result = names.Where(n => n.StartsWith("s")).OrderBy(n=>n);
方法調(diào)用的順序不是固定的,只要Linq方法返回值為IEnumerable類型即可,可以按照容易理解的方式來使用。此規(guī)則適合于以后講到的其他方法。
OrderBy()方法需要傳入一個Lambda表達(dá)式用來告訴它用于排序的方法是什么,我們傳送了最簡單的Lambda表達(dá)式n=>n,因為只需要按照元素本身排序。還可以向上一章所講那樣按照最后一個字母進(jìn)行排序:n=>n.Substring(n.Length-1)
為了給元素逆序排序,可以調(diào)用OrderByDescending()方法,使用方法和OrderBy()相同。
? ?
多級排序可以使用ThenBy()方法。例如:
| var result=list.OrderBy(stu=>stu.Class) .ThenBy(stu=>stu.Age) .ThenBy(stu=>stu.Name) .Select(stu=>new {stu.Name,stu.Age,stu.Class}); |
多字段列表可以用在查詢語法的OrderBy子句中。但在方法語法中第一項排序字段必須使用OrderBy()方法,隨后使用ThenBy()方法。
如果第一個字段是以降序排序,需要使用OrderByDescending()方法,其他字段降序排序需要使用ThenByDescending()方法。
Select()方法用于方法語法的投射。示例5的功能可以通過下面代碼實現(xiàn)。
var result=list.Where(stu=>stu.Age==18)
.Select(stu=>new {stu.Name,stu.Age,stu.Class});
我們常常需要一類查詢,確定數(shù)據(jù)是否滿足某個條件,或者確保所有的數(shù)據(jù)都滿足某個條件。例如,需要確定某個產(chǎn)品是否沒有貨了(庫存為0)。
Linq提供了兩個布爾方法:Any() 和 All(),它們可以快速確定對于數(shù)據(jù)而言,某個條件是true還是false。如下面示例所示:
| bool anyStu = list.Any(stu => stu.Sex == "男"); if (anyStu) { Console.WriteLine("學(xué)員中有男同學(xué)"); } else { Console.WriteLine("學(xué)員中沒有男同學(xué)"); } bool allStu = list.All(stu => stu.Sex == "男"); if (allStu) { Console.WriteLine("學(xué)員中全部是男同學(xué)"); } else { Console.WriteLine("學(xué)員中不全是男同學(xué)"); } |
? ?
Take()方法對應(yīng)SQL語句中的Top運(yùn)算符。與Take()方法相反的是Skip()方法,它可以跳過前n個結(jié)果,返回剩余的結(jié)果。例如:
| var result = list.OrderBy(stu => stu.Age); Console.WriteLine("年齡最小的兩名學(xué)員是:"); foreach (var stu in result.Take(2)) { Console.WriteLine(stu); } Console.WriteLine("其他學(xué)員依次為:"); foreach (var stu in result.Skip(2)) { Console.WriteLine(stu); } |
? ?
First()方法用來查找集合中第一個匹配的元素,如果沒有找到匹配的結(jié)果則會引發(fā)一個異常。可以使用FirstOrDefault()方法避免異常的發(fā)生,若沒有找到則返回有一個空。
示例代碼:
| Console.WriteLine("姓名為lisi的同學(xué)信息:"); Console.WriteLine(list.First(stu => stu.Name == "lisi")); Console.WriteLine("姓名為hanjiu的同學(xué)信息:"); Console.WriteLine(list.FirstOrDefault(stu => stu.Name == "hanjiu")); |
? ?
相當(dāng)于First()和FirstOrDefault(),但是如果不止一個匹配元素則拋出異常。
Count:返回集合的個數(shù)。
Min/Max:返回集合的最小/大值。
Sum:返回集合元素的和。
Average:返回集合元素的平均值。
示例代碼:
| int[] numbers = { 28, 32, 14 }; ? ? int fullCount = numbers .Count(); // 3 int digitCount = "pa55w0rd".Count(c => char.IsDigit(c)); // 3 int smallest = numbers.Min(); // 14; int largest = numbers.Max(); // 32; int smallest = numbers.Max(n => n % 10); // 8; decimal sumTotal = numbers.Sum(); // 15 decimal average = numbers.Average(); // 5 ?? |
? ?
? ?
本文只介紹了Linq的基本用法,尚有很多高級用法有待各位自行查閱資料進(jìn)一步學(xué)習(xí)。
? ?
? ?
? ?
? ?
? ?
? ?
? ?
? ?
? ?
posted @ 2019-04-19 00:22 高原&禿鷲 閱讀(...) 評論(...) 編輯 收藏總結(jié)
以上是生活随笔為你收集整理的APS.NET MVC + EF (01)---Linq和Lambda表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上网软件 Chrome/FireFox插
- 下一篇: 操作系统(五):FCFS/SJF/非抢占