《ASP.NET Core技术内幕与项目实战》精简集-EFCore2.1:LINQ
本节内容,涉及2.3(P40-P51)。主要NuGet包:无
一、常用LINQ方法
1 //测试数据,Employee类型为record 2 //public record Employee(int Id, string Name, int Age, bool Gender, double Salary); 3 4 IEnumerable<Employee> list = new List<Employee>() 5 { 6 new Employee(1, "张三", 18, true, 5000.00), 7 new Employee(2, "李四", 20, false, 5000.00), 8 new Employee(3, "王五", 45, true, 25000.00), 9 new Employee(4, "赵六", 35, false, 16000.00), 10 new Employee(5, "Jack", 26, true, 8000.00), 11 new Employee(6, "Jim", 40, false, 15000.00), 12 new Employee(7, "Tom", 28, false, 7000.00), 13 new Employee(8, "Wow", 37, false, 13500.00), 14 new Employee(9, "Mic", 25, true, 8500.00), 15 new Employee(10, "Bill", 33, true, 13000.00) 16 }; 17 18 19 //Where方法,数据过滤 20 var where1 = list.Where(e => e.Salary > 10000 && e.Age < 40); 21 22 23 //Count方法,数据条数 24 var count1 = list.Count(e => e.Salary > 10000 && e.Age < 40); 25 var count2 = list.Where(e => e.Salary > 10000 && e.Age < 40).Count(); 26 27 28 //Any方法,判断是否至少有一条满足条件的数据 29 var any1 = list.Any(e => e.Salary > 8000); 30 var any2 = list.Where(e => e.Salary > 8000).Any(); 31 32 33 //Single、SingleOrDefault方法,获取一条数据 34 var single1 = list.Single(e => e.Id == 1); //结果返回一条数据 35 //var single2 = list.Single(e => e.Id > 1); //结果报错 36 //var single3 = list.Single(e => e.Id == 11); //结果报错 37 var single4 = list.SingleOrDefault(e => e.Id == 1); //结果返回一条数据 38 //var single6 = list.SingleOrDefault(e => e.Id > 1); //结果报错 39 var single5 = list.SingleOrDefault(e => e.Id == 11); //结果null 40 41 42 //First、FirstOrDefault方法,获取第一条数据 43 var first1 = list.First(e => e.Id > 1); //结果返回第一条 44 //var first2 = list.First(e => e.Id > 11); //结果报错 45 var first3 = list.FirstOrDefault(e => e.Id > 1); //结果返回第一条 46 var first4 = list.FirstOrDefault(e => e.Id > 10); //结果null 47 48 49 //OrderBy、OrderByDescending、ThenBy方法,排序 50 var order1 = list.OrderBy(e => e.Age); //正向排序 51 var order2 = list.OrderByDescending(e => e.Age); //逆向排序 52 var order3 = list.OrderBy(e => e.Age).ThenBy(e => e.Salary); //根据两个字段正向排序 53 54 55 //Skip、Take方法,跳过N条获取N条 56 var st1 = list.Skip(5).Take(5); 57 var st2 = list.Skip(5).Take(10); //不够10条,从第6条开始获取到最后 58 var st3 = list.Skip(5); //跳过5条,一直获取到最后 59 var st4 = list.Take(5); //从第1条开始,获取5条 60 61 62 //Max、Min、Average、Sum方法,聚和函数 63 var max1 = list.Max(e => e.Age); 64 var max2 = list.Where(e => e.Gender == true).Max(e => e.Age); 65 var avg1 = list.Average(e => e.Salary); 66 var avg2 = list.Where(e => e.Id >2).Average(e => e.Salary); 67 int[] scores = { 65, 80, 90 }; 68 var sum1 = scores.Sum(); 69 70 71 //GroupBy方法,分组 72 var group1 = list.GroupBy(e => e.Gender); 73 foreach (var item in group1) 74 { 75 bool gender = item.Key; 76 int count = item.Count(); 77 int maxAge = item.Max(e => e.Age); 78 double avgSalary = item.Average(e => e.Salary); 79 Console.WriteLine($"性别:{gender},人数:{count},最高年龄:{maxAge},平均工资:{avgSalary}。"); 80 } 81 82 83 //Select方法,投影(选取字段) 84 var ages = list.Select(e => e.Age); 85 var genders = list.Select(e => e.Gender ? "男" : "女"); 86 var newList1 = list.Select(e => new { e.Name, e.Age, XingBie = e.Gender ? "男" : "女" }); //匿名类型 87 88 89 //ToArray、ToList方法,集合转换,IEnumerable<T>转换为数组或List集合 90 Employee[] array1 = list.Where(e => e.Salary > 8000).ToArray(); 91 List<Employee> list1 = list.Where(e => e.Salary > 8000).ToList(); 92 93 94 //链式调用,综合应用,Where、Select、OrderBy、GroupBy、Take、Skip等返回IEnumerable<T>的方法,可以链式调用 95 var linkList = list.Where(e => e.Id >= 2).GroupBy(e => e.Gender).OrderBy(g => g.Key).Take(3) 96 .Select(g => new {XingBie = g.Key?"男":"女", AvgSalary = g.Average(e => e.Salary)}); 97 foreach (var item in linkList) 98 { 99 Console.WriteLine(item); 100 }
补充说明:
①LINQ方法,实质为IEnumerable<T>的扩展方法,存在于System.Linq命名空间的静态类中。这些方法,也基本可以使用于EFCore中的IQuerable<T>
②在EFCore中使用LINQ时,可以使用“LINQPad”辅助编写和调试
二、LINQ方法的原理
1 internal class Program 2 { 3 static void Main(string[] args) 4 { 5 //委托 6 MyDelegate d1 = SayEnglish; 7 SayEnglish(23); 8 d1 = SayChinese; 9 SayChinese(23); 10 11 static void SayEnglish(int age) 12 { 13 Console.WriteLine($"I am {age} years old."); 14 } 15 16 static void SayChinese(int age) 17 { 18 Console.WriteLine($"我已经 {age} 岁了。"); 19 } 20 21 22 //匿名委托 23 Func<int, int, int> f0 = delegate (int a, int b) 24 { 25 return a + b; 26 }; 27 Console.WriteLine(f0(2,3)); 28 29 30 //Lambda表达式 31 Func<int, int, int> f1 = (int a, int b) => { return a + b; }; 32 Console.WriteLine(f1(2, 3)); 33 34 Func<int, int, int> f2 = (a, b) => a + b; 35 Console.WriteLine(f2(2, 3)); 36 37 Func<int, bool> f3 = a => a > 0; 38 Console.WriteLine(f3(1)); 39 40 41 //实现Where 42 int[] arrays = { 1, 2, 3 }; 43 44 var newArrays = MyWhere(arrays, n => n >= 2); 45 Console.WriteLine(String.Join(",",newArrays)); 46 47 static IEnumerable<int> MyWhere(IEnumerable<int> nums, Func<int, bool> filter) 48 { 49 foreach (int n in nums) 50 { 51 if (filter(n)) 52 { 53 yield return n; 54 } 55 } 56 } 57 } 58 } 59 60 delegate void MyDelegate(int n);
代码解读:
6-19行:自定义MyDelegate委托类型,并创建d1变量,先后指向SayEnglish和SayChinese方法。委托类型定义的参数和返回值,要与委托变量指向的方法保持一致。
23-27行:使用框架自定义的Func泛型委托类型,创建委托变量fo,指向一个匿名方法(没有方法名称),这样不需要单独定义方法。
31-38行:使用框架自定义的Func泛型委托类型,创建委托变量f1、f2、f3,分别指向相应的Lambda方法,注意不同的简写方式
42-56行:利用委托变量,将方法作为参数传入方法,实现类似LINQ的Where方法。yield return为迭代器实现
补充说明:
①Func<T1,T2...Tn>委托类型,最后一个类型参数Tn为返回值,其余为方法参数;Action<T1,T2...Tn>委托类型,所有类型参数均为方法参数
特别说明:
1、本系列内容主要基于杨中科老师的书籍《ASP.NET Core技术内幕与项目实战》及配套的B站视频视频教程,同时会增加极少部分的小知识点
2、本系列教程主要目的是提炼知识点,追求快准狠,以求快速复习,如果说书籍学习的效率是视频的2倍,那么“简读系列”应该做到再快3-5倍