一篇文章教你学会ASP.Net Core LINQ基本操作
一篇文章教你学会ASP.Net Core LINQ基本操作
为什么要使用LINQ
LINQ中提供了很多集合的扩展方法,配合lambda能简化数据处理。
例如我们想要找出一个IEnumerable<int>
中所有大于10的元素,使用LINQ则可以这样写
static void Main(string[] args)
{
int[] nums = new int[] { 3, 5, 6, 5, 10, 12, 14, 7 };
IEnumerable<int> res = nums.Where(a => a > 10);
foreach (int i in res)
Console.WriteLine(i);
}
其中使用IEnumerable
要using System.Collections.Generic;
使用Where
方法要using System.Linq;
,该方法会遍历每个元素然后去判断是否大于10
LINQ背后原理
为了解LINQ背后的原理,我们首先去实现一个简单的Where
方法
第一种方案:
static IEnumerable<int> MyWhere1(IEnumerable<int> items, Func<int, bool> f)
{
List<int> res = new List<int>();
foreach (int i in items)
if (f(i) == true)
res.Add(i);
return res;
}
第二种方案:
static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
{
List<int> res = new List<int>();
foreach (int i in items)
if (f(i) == true)
yield return i;
}
那么这两种方案的区别是什么?第一种方案是把所有元素全部检查一遍,把符合要求的元素放到List<int> res
里面,然后返回res
;然而第二种方案使用yield
,是一种“流水线”方式处理,找到符合条件的元素立即返回,返回后Console.WriteLine
立即能够打印,从而提高了数据处理效率。
LINQ的常用扩展方法
LINQ提供了很多扩展方法,大部分都在System.Linq
命名空间中。
接下来准备一些数据,用于下面的操作。
首先定义一个员工类,里面有姓名工资等成员。
class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Gender { get; set; }
public int Salary { get; set; }
public override string ToString()
{
return $"ID={Id}, Name={Name}, Age={Age}, Gender={Gender}, Salary={Salary}";
}
}
然后再Main方法中创建实例导入数据,并将所有实例保存到列表中。
List<Employee> lst = new List<Employee>();
lst.Add(new Employee { Id = 1, Name = "jerry", Age = 28, Gender = true, Salary = 5000 });
lst.Add(new Employee { Id = 2, Name = "jim", Age = 33, Gender = true, Salary = 3000 });
lst.Add(new Employee { Id = 3, Name = "lily", Age = 35, Gender = false, Salary = 9000 });
lst.Add(new Employee { Id = 4, Name = "lucy", Age = 16, Gender = false, Salary = 2000 });
lst.Add(new Employee { Id = 5, Name = "kimi", Age = 25, Gender = true, Salary = 1000 });
lst.Add(new Employee { Id = 6, Name = "nancy", Age = 35, Gender = false, Salary = 8000 });
lst.Add(new Employee { Id = 7, Name = "zack", Age = 35, Gender = true, Salary = 8500 });
lst.Add(new Employee { Id = 8, Name = "jack", Age = 33, Gender = true, Salary = 8000 });
Where方法
该方法会遍历每个元素然后去判断是否符合条件,符合条件的元素则被返回。
IEnumerable<Employee> res = lst.Where(e => e.Age > 20); //把年龄大于20的返回过来
foreach (Employee e in res)
Console.WriteLine(e);
返回结果
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
ID=2, Name=jim, Age=33, Gender=True, Salary=3000
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
ID=6, Name=nancy, Age=35, Gender=False, Salary=8000
ID=7, Name=zack, Age=35, Gender=True, Salary=8500
ID=8, Name=jack, Age=33, Gender=True, Salary=8000
Count方法
该方法会返回符合条件的元素的个数
Console.WriteLine(lst.Count(e=>e.Salary>8000));
返回结果
2
Any方法
该方法会判断是否存在至少一个元素符合条件。另外,如果传入的参数为空,则会判断IEnumerable
(或者实现了IEnumerable
接口的其他类,如List
)是否存在元素。
如以下代码
List<int> test = new List<int>();
Console.WriteLine(test.Any());
由于列表为空,test.Any()
返回的就是false
如果判断是否存在Employee
类型的元素于lst
中,则代码如下,其返回值为true
Console.WriteLine(lst.Any(e=>e.Salary>8000));
同样的,我们使用Count
方法也可以达成此目的(判断返回元素个数是否为0),但是Count
方法相对于Any
方法效率较低。
这是因为Any
找到一个符合条件的元素会立即返回,而Count
方法是统计个数,找到一个符合元素后还要继续向后找。
有关一条数据的方法
有关一条数据的方法有好几种,不过在细节上略有不一样,所以我们把他们放一块介绍。
方法 | 描述 |
---|---|
Single() |
有且只有一条满足要求的数据 |
SingleOrDefault() |
最多只有一条满足要求的数据 |
First() |
至少有一条,并且返回第一条 |
FirstOrDefault() |
返回第一条或默认值 |
Signle方法
Employee elem = lst.Single(e => e.Salary > 8000); //错误,有多条数据满足条件
Employee elem = lst.Single(e => e.Salary > 8500); //正确,仅一条数据满足条件
SingleOrDefault方法
对于SingleOrDefault
,当且仅当存在一条数据满足条件,返回该数据;如果存在多条则报错;如果不存在则返回默认值。
Employee elem = lst.SingleOrDefault(e=>e.Salary>8000); //错误,有多条数据满足条件
Employee elem = lst.SingleOrDefault(e=>e.Salary>8500); //正确,仅一条数据满足条件
下面我们来看下默认值的情况
int[] nums = new int[] { 1, 2, 3 };
int i = nums.SingleOrDefault(i => i > 10);
Console.WriteLine(i);
由于不存在大于10的整型数字,所以该方法返回变量i
的默认值,输出结果为0
First方法
该方法要求数据至少有一条满足条件,并且只返回查询到的第一条数据。
Employee test = lst.First(e=>e.Salary>9000); //报错,不存在数据满足条件
//正确,满足年龄大于16的有多条,仅按照我们添加数据的顺序返回第一条
Employee test = lst.First(e=>e.Age>16);
Console.WriteLine(test);
输出结果
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
FirstOrDefault方法
该方法返回符合条件的第一条数据,否则返回默认值
如下方代码,从数组中返回一个大于2的整数,其输出结果为3
int[] nums = new int[] { 1, 2, 3, 4, 5, 6 };
int i = nums.FirstOrDefault(e => e > 2);
Console.WriteLine(i);
我们再来看看返回默认值的情况
int[] nums = new int[] { 1, 2, 3, 4, 5, 6 };
int i = nums.FirstOrDefault(e => e > 10);
Console.WriteLine(i);
由于数组中不存在大于10的数,所以i
的值就是其默认值0
排序方法
一般排序
排序方法有两种
方法 | 描述 |
---|---|
OrderBy() |
正序排序 |
OrderByDescending() |
逆序排序 |
二者用法几乎一致,此处仅演示OrderBy
方法
IEnumerable<Employee> res2 = lst.OrderBy(e => e.Age);
foreach (Employee e in res2)
Console.WriteLine(e);
其输出结果为
ID=4, Name=lucy, Age=16, Gender=False, Salary=2000
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
ID=2, Name=jim, Age=33, Gender=True, Salary=3000
ID=8, Name=jack, Age=33, Gender=True, Salary=8000
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=6, Name=nancy, Age=35, Gender=False, Salary=8000
ID=7, Name=zack, Age=35, Gender=True, Salary=8500
很显然数据已经按照年龄从小至大的顺序进行排序了。
此外应该注意的是,该方法必须有参数。如果想要对一个数组进行排序,正确写法如下
int[] nums2 = new int[] { 3, 1, 2, 4, 5, 6 };
IEnumerable<int> resNum = nums2.OrderBy(i => i);
//写成nums2.OrderBy()是错误的
多排序
所谓多排序,就是按照一个条件对数据进行排序后,存在多个数据该条件下的值一致,然后再对这些值一致的数据按照其他条件排序。
其方法也有两个,一般是在OrderBy()
或OrderByDescending()
之后调用
方法 | 描述 |
---|---|
ThenBy() |
正序再排序 |
ThenByDescending() |
逆序再排序 |
我们对文章上方的数据首先按照对年龄进行排序,然后对年龄一致的员工再按照工资进行逆排序,编写代码如下:
IEnumerable<Employee> sortTest = lst.OrderBy(x => x.Age).ThenByDescending(x => x.Salary);
foreach (Employee emp in sortTest)
Console.WriteLine(emp);
输出如下:
ID=4, Name=lucy, Age=16, Gender=False, Salary=2000
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
ID=8, Name=jack, Age=33, Gender=True, Salary=8000
ID=2, Name=jim, Age=33, Gender=True, Salary=3000
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=7, Name=zack, Age=35, Gender=True, Salary=8500
ID=6, Name=nancy, Age=35, Gender=False, Salary=8000
限制结果集的方法
限制结果集,获取部分数据的方法一般是利用Skip
和Take
方法
例如我想要从上述员工数据中,获取从第2条开始连续的3条数据,则代码可以这样写;
IEnumerable<Employee> sortTest = lst.Skip(2).Take(3);
foreach (Employee emp in sortTest)
Console.WriteLine(emp);
其输出结果如下:
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=4, Name=lucy, Age=16, Gender=False, Salary=2000
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
当然,Skip
方法和Take
方法也可以单独使用:
Take单独使用
IEnumerable<Employee> sortTest = lst.Take(3);
foreach (Employee emp in sortTest)
Console.WriteLine(emp);
输出:
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
ID=2, Name=jim, Age=33, Gender=True, Salary=3000
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
Skip单独使用
IEnumerable<Employee> sortTest = lst.Skip(2);
foreach (Employee emp in sortTest)
Console.WriteLine(emp);
输出:
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=4, Name=lucy, Age=16, Gender=False, Salary=2000
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
ID=6, Name=nancy, Age=35, Gender=False, Salary=8000
ID=7, Name=zack, Age=35, Gender=True, Salary=8500
ID=8, Name=jack, Age=33, Gender=True, Salary=8000
聚合函数(方法)
LINQ聚合函数常用的有这些,但应当注意的是它们的返回值类型不与其他LINQ的方法一样是IEnumerable
,而是条件的值的类型。
方法 | 描述 |
---|---|
Max() |
返回给定条件的最大值 |
Min() |
返回给定条件的最小值 |
Average() |
返回给定条件的平均值 |
Sum() |
返回给定条件的和 |
Count() |
统计满足条件的数据的个数 |
这些方法用法大致相同,甚至Count
方法在上文中已经介绍过,此处仅用Max
方法演示
int maxSalary = lst.Max(x => x.Salary);
Console.WriteLine(maxSalary);
该样例会输出所有员工的最大工资(请注意maxSalary的类型)
如果想要找到大于30岁的员工的最高工资,则可以
int maxSalary = lst.Where(x=>x.Age > 30).Max(x => x.Salary);
GroupBy方法
该方法用于对数据分组,其参数是分组条件表达式,返回值为IGrouping<TKey, TSource>
类型的泛型IEnumerable。
我们编写代码来实现很具年龄分组:
IEnumerable<IGrouping<int, Employee>> items = lst.GroupBy(x => x.Age);
foreach (var item in items)
{
Console.WriteLine($"年龄为{item.Key}的分组成员有:");
foreach (var i in item)
Console.WriteLine(i);
Console.WriteLine();
}
其输出结果为:
年龄为28的分组成员有:
ID=1, Name=jerry, Age=28, Gender=True, Salary=5000
年龄为33的分组成员有:
ID=2, Name=jim, Age=33, Gender=True, Salary=3000
ID=8, Name=jack, Age=33, Gender=True, Salary=8000
年龄为35的分组成员有:
ID=3, Name=lily, Age=35, Gender=False, Salary=9000
ID=6, Name=nancy, Age=35, Gender=False, Salary=8000
ID=7, Name=zack, Age=35, Gender=True, Salary=8500
年龄为16的分组成员有:
ID=4, Name=lucy, Age=16, Gender=False, Salary=2000
年龄为25的分组成员有:
ID=5, Name=kimi, Age=25, Gender=True, Salary=1000
通过打印我们可以发现IEnumerable
元素为IGrouping
类型,其键与值对应关系是一对多的。在这里每个元素的键就是年龄,而值为具有相同年龄的Employee
类型的员工数据。
投影与匿名类型
投影是把集合中每一项转化为另外一种类型。
IEnumerable<string> items = lst.Where(x => x.Salary > 5000).Select(x => x.Gender ? "男" : "女");
foreach (var item in items)
Console.WriteLine(item);
输出结果为:
女
女
男
男
匿名类型没有名称,所以我们没有办法去用类型名去声明它,而是需要用到var
关键字
var items = lst.Select(e => new
{
XingMing = e.Name,
NianLing = e.Age,
Xingbie = e.Gender ? "男" : "女"
});
foreach (var item in items)
Console.WriteLine(item);
其输出结果为:
{ XingMing = jerry, NianLing = 28, Xingbie = 男 }
{ XingMing = jim, NianLing = 33, Xingbie = 男 }
{ XingMing = lily, NianLing = 35, Xingbie = 女 }
{ XingMing = lucy, NianLing = 16, Xingbie = 女 }
{ XingMing = kimi, NianLing = 25, Xingbie = 男 }
{ XingMing = nancy, NianLing = 35, Xingbie = 女 }
{ XingMing = zack, NianLing = 35, Xingbie = 男 }
{ XingMing = jack, NianLing = 33, Xingbie = 男 }
类型转换
在实际使用中,我们往往不是一定用IEnumerable
,还有可能是List
等,所以需要用到类型转换
例如我们利用Where
方法返回工资大于6000的员工存放到IEnumerable
中,然后将其转化为List
类型
List<Employee> lst2 = lst.Where(e => e.Salary > 6000).ToList();
此外还有ToArray
等方法,此处不过多说明。
链式调用
所谓链式调用就是调用完一个函数(方法)后还能再后面继续跟着调用其它函数(方法)。
由于LINQ绝大多数方法返回的都是IEnumerable
方法,而且绝大部分都是针对IEnumerable
接口,所以可以在调用方法后继续调用其他方法。
lst.Where(e => e.Salary > 6000).ToList();
例如我们定义数组
int[] nums = new int[] { 1, 2, 3, 4, 5, 6 };
在小于3的元素中选取最大值
int a = nums.Where(x=>x<3).Max();
对于上面这行nums.Where(x=>x<3).Max()
在Where
方法后加一个点然后再调用Max
方法的形式就叫做链式调用。
查询语法
对于上述的使用Where
、Select
等扩展方法进行数据查询的写法叫做LINQ方法语法。
然而还有一种叫做查询语法。
我们同样定义一个数组演示
int[] nums = new int[] { 6,5,4,3,2,1 };
我们取小于3的元素,然后进行正序排序,则用查询语法则可以如下:
var items = from e in nums
where e < 3
orderby e
select e;
这里需要注意,查询语法需要以select或group子句结尾
那么问题来了,方法语法与查询语法有什么区别?我们可以用方法语法写一段相同效果的语法,然后用反编译器(ILSpy)去看一下代码。
其反编译结果给出了查询语法的形式,然后对查询语法生成文件进行反编译,发现结果相同,这说明两种方法在编译后没有任何区别只是写法不同
结束
LINQ的基本操作大致就这些,感谢杨中科老师提供的课程
一篇文章教你学会ASP.Net Core LINQ基本操作的更多相关文章
- 一篇文章教你学会基础的HTML
html是学习做网页的基础,漂亮的网页与布局就是由有些html代码组成,大家看完这篇文章就可以简单的了解html了,多写多练 如果你不致力于成为美工的话,那么作为开发人员,可以读懂HTML.必 ...
- 一篇文章教你如何部署.NET Core WPF应用,你还在等什么?
DevExpress广泛应用于ECM企业内容管理. 成本管控.进程监督.生产调度,在企业/政务信息化管理中占据一席重要之地.通过DevExpress WPF Controls,您能创建有着强大互动功能 ...
- 一篇文章教你如何用R进行数据挖掘
一篇文章教你如何用R进行数据挖掘 引言 R是一种广泛用于数据分析和统计计算的强大语言,于上世纪90年代开始发展起来.得益于全世界众多 爱好者的无尽努力,大家继而开发出了一种基于R但优于R基本文本编辑器 ...
- win10 uwp 手把手教你使用 asp dotnet core 做 cs 程序
本文是一个非常简单的博客,让大家知道如何使用 asp dot net core 做后台,使用 UWP 或 WPF 等做前台. 本文因为没有什么业务,也不想做管理系统,所以看到起来是很简单. Visua ...
- [转]教你实践ASP.NET Core Authorization
本文转自:http://www.cnblogs.com/rohelm/p/Authorization.html 本文目录 Asp.net Core 对于授权的改动很友好,非常的灵活,本文以MVC为主, ...
- 教你实践ASP.NET Core Authorization
本文目录 Asp.net Core 对于授权的改动很友好,非常的灵活,本文以MVC为主,当然如果说webapi或者其他的分布式解决方案授权,也容易就可以实现单点登录都非常的简单,可以使用现成的Iden ...
- [亲测]七步学会ASP.NET Core 2.0怎么发布/部署到Ubuntu Linux服务器并配置Nginx反向代理实现域名访问
前言 ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用ASP.NET Core网站绑定到指定的域名,让外网用户可以访问呢? 步骤 第1步:准备工作 一台Liun ...
- 一篇文章带你学会Linux三剑客之一:awk
awk是一种用于处理文本.模式匹配的编程语言.与sed和grep,俗称Linux下的三剑客.学会 awk 等于你在 Linux 命令行里,又多了一种处理文本的选择.这篇文章重点教你如何使用,看完这篇文 ...
- 一篇文章教你读懂Makefile
makefile很重要 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professiona ...
随机推荐
- mysql InnoDB通过.frm和.ibd恢复表和数据
ibdata1是一个用来构建innodb系统表空间的文件,这个文件包含了innodb表的元数据.撤销记录.修改buffer和双写buffer.如果file-per-table选项打开的话,该文件则不一 ...
- VisionPro · C# · 加密狗检查程序
写VisionPro C#项目时,我们需要在程序的启动时加载各种配置文件,以及检查软件授权,以下代码即检查康耐视加密狗在线状态,如查无加密狗,关闭程序启动进程并抛出异常. 1 using System ...
- MySQL十种锁,一篇文章带你全解析
MySQL有两个核心的知识点,索引和锁.前几篇文章已经详细讲解了MySQL索引实现机制,今天再一起学习一下MySQL的锁. 1 为什么要加锁? 当多个事务并发操作同一批数据的时候,如果不加锁,就无法保 ...
- Entry键值对对象和Map集合遍历键值对方式
我们已经知道,Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在IMap 中是一一对应关系, 这一对对象又称做Map 中的一个Entry(项).Entry将键值对的对应 ...
- 2020 CSP-J 初赛解析
题面 老师给的解析 自己觉得很好的一篇题解 直接说重点题吧,不耽误时间了 T5: 这个很显然就是让进这个 while 的次数尽可能少, 那么我们可以让他只进一次 while,即让第一次进 whil ...
- 👨💻Mybatis源码我搞透了,面试来问吧!写了134个源码类,1.03万行代码!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言:手撸一万行! 完结撒花:4个月.20章.134个类.1.03万行代码! 22年3月初 ...
- CTCLoss如何使用
CTCLoss如何使用 目录 CTCLoss如何使用 什么是CTC 架构介绍 一个简单的例子 CTC计算的推导 总概率\(p(z|x)\) 路径的含义 路径概率\(p(\pi|x)\) 什么是\(\m ...
- java面试题(2022最新)
1.String是基本数据类型么?不是基本数据类型,byte int char long flout duable boolem short 2.int 和integer区别int是基本数据类型,in ...
- 001 Redis 配置
Redis缓存 1.配置Redis //Redis 配置文件 @Configuration public class RedisConfiguration { @Bean public RedisTe ...
- 了解有哪几个C标准&了解C编译管道
下列哪个不是C标准.参考:C语言标准 小知识:C语言标准的发展 K&R C: 1978年,丹尼斯·里奇(Dennis Ritchie)和布莱恩·科尔尼干(Brian Kernighan)出版了 ...