C#进阶-LINQ表达式基础语法

举报
Damon小智 发表于 2024/04/30 14:25:02 2024/04/30
【摘要】 本篇文章我们将演示LINQ扩展包的基础语法,以Select查询、Count计数、Average平均值、OrderBy排序函数为例,目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。

本篇文章我们将演示LINQ扩展包的基础语法,以Select查询、Count计数、Average平均值、OrderBy排序函数为例,目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。


一、LINQ表达式学前准备

在学习之前,我们要做一些准备工作,我们需要创建User对象和包含User对象的集合,作为后面查询和输出的数据源。

1、C#代码准备

C#类:

class User
{
    public int id { get; set; } 
    public string name { get; set; } 
    public bool gender { get; set; }//male: true; female: fasle
    public int age { get; set; }
    public string occupation { get; set; } //职业
}
List<User> list = new List<User>()
{
    new User { id = 1, name = "Zhang Long", age = 38, gender = true, occupation = "Teacher"},
    new User { id = 2, name = "Zhang Jin", age = 18, gender = false, occupation = "Student"},
    new User { id = 3, name = "Zhang Shuai", age = 38, gender = false, occupation = "Teacher"},
    new User { id = 4, name = "Liu Guangzhi", age = 38, gender = false, occupation = "Doctor"},
    new User { id = 5, name = "Liu Ziming", age = 38, gender = true, occupation = "Doctor"},
    new User { id = 6, name = "Liu Shuai", age = 29, gender = false, occupation = "Doctor"},
    new User { id = 7, name = "Liu Jin", age = 21, gender = true, occupation = "Builder"},
    new User { id = 8, name = "Jiang Long", age = 38, gender = true, occupation = "Builder"},
    new User { id = 9, name = "Hu Ziming", age = 21, gender = true, occupation = "Student"},
    new User { id = 10, name = "Hu Jin", age = 21, gender = false, occupation = "Student"}
};

2、数据库准备

SQL数据源:

image.png


二、LINQ表达式基础语法示例

1、Select 查询

/* SQL里的表达: 查找用户里职业是医生的人的姓名,按照年龄倒序输出 */
select name from user where occupation = "Doctor" order by age desc;
/* C#版本1 */
List<string> nameList = (from u in list where u.occupation == "Doctor" orderby u.age descending select u.name).ToList();
/* C#版本2 */
List<string> nameList = list.OrderByDescending(u => u.age).Where(p => p.occupation == "Doctor").Select(x => x.name).ToList();

image.png

Liu Guangzhi, Liu Ziming, Liu Shuai /* 输出结果 */

其中,C#版本1的语法是 from 变量名 in 集合 where 条件 orderby 条件 select 结果变量,得到的结果是LINQ的内置类型<Enumerable>,可直接视为匿名类型(var),需用.ToList()转换为List<string>类型。C#版本2是LINQ的一种扩展写法,是更加常用的写法。


2、Count 计数

/* SQL里的表达: 查找用户里姓Zhang的女性教师的数量*/
select count(*) from user where occupation = "Teacher" and name like 'Zhang%' and gender = false;
/* C#版本1 */
int count = (from u in list where u.occupation == "Teacher" where !u.gender where u.name.StartsWith("Zhang") select u).Count();
/* C#版本2 */
int count = list.Count(u => u.occupation == "Teacher" && !u.gender && u.name.StartsWith("Zhang"));

image.png

1 /* 输出结果 */

3、Average 平均值

/* SQL里的表达: 查找用户里的小于40岁的某姓医生的平均年龄 */
select avg(age) from user where occupation = "Doctor" and name like 'Liu%' and age < 40;
/* C#版本1 */
double averageNum = (from u in list where u.occupation == "Doctor" where u.age<40 where u.name.StartsWith("Liu") select u.age).Average();
/* C#版本2 */
double averageNum = list.Where(u => u.occupation == "Doctor" && u.age < 40 && u.name.StartsWith("Liu")).Select(u => u.age).Average();

image.png

35 /* 输出结果 */

4、Max/Min/Sum/ 最大/小值/总和

这里仅需参考LINQ求平均值的例子,求最大/小值或者总和时,只需要把C#语句末尾的.Average()方法替换成.Max()/.Min()/.Sum()即可。


5、OrderBy 排序

/* SQL里的表达: 查找用户里名字带Jin的人,优先按照年龄倒序,其次按照姓氏拼音正序,输出这些人的全部信息 */
select * from user where name like '%Jin%' order by  age desc name asc;
/* C#版本1 */

List<User> userList = (from u in list where u.name.Contains("Jin") orderby u.age descending orderby u.name select u).ToList();
/* C#版本2 */

List<User> userList = list.Where(u => u.name.Contains("Jin")).OrderByDescending(u => u.age).OrderBy(u => u.name).ToList();

image.png

{id = 10, name = Hu Jin, age = 21, gender = False, occupation = Student}, 
{id = 7, name = Liu Jin, age = 21, gender = True, occupation = Builder}, 
{id = 2, name = Zhang Jin, age = 18, gender = False, occupation = Student} /* 输出结

6、Any/All 函数

Any()函数判断判断是否至少存在一个符合元素符合条件;All()函数判断是否全部元素都符合条件;下面以Any()函数为例:

/* SQL里的表达: 查找用户里是否存在年龄小于30岁职业是医生的女性 */
select count(*) from user where occupation = "Doctor" and gender = false and age < 30; //返回符合的个数
/* C#版本1 */
bool result = (from u in list where u.age < 30 where !u.gender where u.occupation == "Doctor" select u).Any();
/* C#版本2 */
bool result = list.Any(u => u.age < 30 && !u.gender && u.occupation == "Doctor");

数据源中所有医生如下:

image.png

可以看到,目前我们数据源里是有Liu Shuai这一条符合三个属性(小于30岁/医生/女性)的。

true /* 输出结果 */

这里Any()函数是只要存在至少一个符合全部条件的结果,即返回布尔值True,只有在一个都不符合条件的情况下才会返回False;与之相反,All()函数只有在全部数据都符合全部条件的情况下,才会返回True,只要有一条不满足就返回False;All()函数的语法和Any()函数的语法相同,上面的例子把Any()直接替换成All()即可。


7、Single/SingleOrDefault 函数

Single()判断是否只有一个元素符合条件,若成立则返回该元素,若不成立则抛出异常。

/* SQL里的表达: 查找用户里年龄小于30岁职业是医生的女性 */
select * from user where occupation = "Doctor" and gender = false and age < 30
/* C#版本1 */
User userResult = (from u in list where u.age < 30 where !u.gender where u.occupation == "Doctor" select u).Single();
/* C#版本2 */
User userResult = list.Single(u => u.age < 30 && !u.gender && u.occupation == "Doctor");

image.png

{id = 6, name = Liu Shuai, age = 29, gender = False, occupation = Doctor} /* 输出结果 */

Single()要求有且只有一条满足要求的数据,多条满足条件或一条也没有,此方法会报错;
SingleOrDefault()要求最多有一条满足要求的数据,多条满足条件,此方法会报错;没有数据则返回数据类型的默认值;
类似的还有First()、FirstOrDefault()、Last()、LastOrDefault(),这里给大家做了一个异常表格记录了各种情况的返回值:

函数 没有满足 一条满足 多条满足 list本身为Null
Single 异常 该元素 异常 异常
SingleOrDefault 默认值 该元素 异常 异常
First 异常 该元素 第一个元素 异常
FirstOrDefault 默认值 该元素 第一个元素 异常
Last 异常 该元素 末尾的元素 异常
LastOrDefault 默认值 该元素 末尾的元素 异常

面对可能出现的异常,我们一般在使用这类方法时要进行Try{…}Catch(…){…}。


8、Skip/Take/Top 函数

/* SQL里的表达: 查找用户表自然排序第4个人到第6个人的姓名*/
select name from user limit 3,3;
/* C#版本1 */
List<string> nameList = (from u in list select u.name).Skip(3).Take(3).ToList();
/* C#版本2 */
List<string> nameList = list.Skip(3).Take(3).Select(x => x.name).ToList();

image.png

Liu Guangzhi, Liu Ziming, Liu Shuai /* 输出结果 */

同理,Top(n)表示截取前n条数据。


三、LINQ表达式总结

在现代编程中,Linq(Language Integrated Query)表达式是.NET语言中的一项强大功能,允许开发者以声明式方式查询和操作数据。Linq可以用于各种数据源,包括数组、列表、XML文件以及数据库。本部分将总结Linq的关键特性,并通过一个同类程序集的对比表格,展示Linq在不同环境下的应用与效能。

1、LINQ表达式的特点

  • 集成性:Linq表达式完美集成于C#和VB.NET等语言,提供一致的查询能力。
  • 可读性:Linq语法简洁,易于编写和理解,大大提高了代码的可读性。
  • 强类型:Linq是强类型的,这意味着在编译时就可以检查类型错误,提高程序的稳定性。
  • 多数据源支持:Linq不限于查询数据库,还可以操作数组、列表等多种数据结构。

2、LINQ与同类程序集的对比

程序集 数据源支持 性能表现 易用性评分 特点
Linq to SQL SQL数据库 5/5 直接与SQL Server交互
Linq to XML XML文件 4/5 简化XML数据处理
Linq to Entities 关系型和非关系型数据库 5/5 支持复杂的数据查询和操作
Linq to Objects 内存中的对象集合 5/5 适用于小型集合的快速查询

3、LINQ表达式总结

Linq技术为.NET开发者提供了一个强大的工具,能够简化复杂数据操作并整合不同的数据源。其语法的统一性和强类型特征使得开发过程中数据操作更加安全,同时也更加直观。尽管在处理非常大的数据集时性能可能会成问题,但对于大多数日常开发任务而言,Linq提供了既高效又易用的解决方案。通过使用Linq,开发者可以减少代码量,提高代码质量,并能更好地维护和扩展其应用程序。无论是在企业级应用还是在小型项目中,Linq都证明了自己的价值,是.NET生态中不可或缺的一部分。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。