基础语法
在学习之前,我们要做一些准备工作,我们需要创建User对象和包含User对象的集合,作为后面查询和输出的数据源,参见这篇文章C#进阶之LINQ表达式总结完成准备工作。
数据源:
1、Select 查询
/* SQL里的表达: 查找用户里职业是医生的人的姓名,按照年龄倒序输出 */selectnamefromuserwhereoccupation="Doctor"orderbyagedesc;
/* C#版本1 */List<string>nameList= (fromuinlistwhereu.occupation=="Doctor"orderbyu.agedescendingselectu.name).ToList(); /* C#版本2 */List<string>nameList=list.OrderByDescending(u=>u.age).Where(p=>p.occupation=="Doctor").Select(x=>x.name).ToList();
LiuGuangzhi, LiuZiming, LiuShuai/* 输出结果 */
其中,C#版本1的语法是 from 变量名 in 集合 where 条件 orderby 条件 select 结果变量,得到的结果是LINQ的内置类型<Enumerable>,可直接视为匿名类型(var),需用.ToList()转换为List<string>类型。C#版本2是LINQ的一种扩展写法,是更加常用的写法。
2、Count 计数
/* SQL里的表达: 查找用户里姓Zhang的女性教师的数量*/selectcount(*) fromuserwhereoccupation="Teacher"andnamelike'Zhang%'andgender=false;
/* C#版本1 */intcount= (fromuinlistwhereu.occupation=="Teacher"where!u.genderwhereu.name.StartsWith("Zhang") selectu).Count(); /* C#版本2 */intcount=list.Count(u=>u.occupation=="Teacher"&&!u.gender&&u.name.StartsWith("Zhang"));
1/* 输出结果 */
3、Average 平均值
/* SQL里的表达: 查找用户里姓Liu的小于40岁的医生的平均年龄 */selectavg(age) fromuserwhereoccupation="Doctor"andnamelike'Liu%'andage<40;
/* C#版本1 */doubleaverageNum= (fromuinlistwhereu.occupation=="Doctor"whereu.age<40whereu.name.StartsWith("Liu") selectu.age).Average(); /* C#版本2 */doubleaverageNum=list.Where(u=>u.occupation=="Doctor"&&u.age<40&&u.name.StartsWith("Liu")).Select(u=>u.age).Average();
35/* 输出结果 */
4、Max/Min/Sum/ 最大/小值/总和
这里仅需参考LINQ求平均值的例子,求最大/小值或者总和时,只需要把C#语句末尾的.Average()方法替换成.Max()/.Min()/.Sum()即可。
5、OrderBy 排序
/* SQL里的表达: 查找用户里名字带Jin的人,优先按照年龄倒序,其次按照姓氏拼音正序,输出这些人的全部信息 */select*fromuserwherenamelike'%Jin%'orderbyagedescnameasc;
/* C#版本1 */List<User>userList= (fromuinlistwhereu.name.Contains("Jin") orderbyu.agedescendingorderbyu.nameselectu).ToList(); /* C#版本2 */List<User>userList=list.Where(u=>u.name.Contains("Jin")).OrderByDescending(u=>u.age).OrderBy(u=>u.name).ToList();
{id=10, name=HuJin, age=21, gender=False, occupation=Student}, {id=7, name=LiuJin, age=21, gender=True, occupation=Builder}, {id=2, name=ZhangJin, age=18, gender=False, occupation=Student} /* 输出
6、 Any/All 函数
Any()函数判断判断是否至少存在一个符合元素符合条件;All()函数判断是否全部元素都符合条件;下面以Any()函数为例:
/* SQL里的表达: 查找用户里是否存在年龄小于30岁职业是医生的女性 */selectcount(*) fromuserwhereoccupation="Doctor"andgender=falseandage<30; //返回符合的个数
/* C#版本1 */boolresult= (fromuinlistwhereu.age<30where!u.genderwhereu.occupation=="Doctor"selectu).Any(); /* C#版本2 */boolresult=list.Any(u=>u.age<30&&!u.gender&&u.occupation=="Doctor");
数据源中所有医生如下:
可以看到,目前我们数据源里是有Liu Shuai这一条符合三个属性(小于30岁/医生/女性)的。
true/* 输出结果 */
这里Any()函数是只要存在至少一个符合全部条件的结果,即返回布尔值True,只有在一个都不符合条件的情况下才会返回False;与之相反,All()函数只有在全部数据都符合全部条件的情况下,才会返回True,只要有一条不满足就返回False;All()函数的语法和Any()函数的语法相同,上面的例子把Any()直接替换成All()即可。
7、Single/SingleOrDefault 函数
Single()判断是否只有一个元素符合条件,若成立则返回该元素,若不成立则抛出异常。
/* SQL里的表达: 查找用户里年龄小于30岁职业是医生的女性 */select*fromuserwhereoccupation="Doctor"andgender=falseandage<30
/* C#版本1 */UseruserResult= (fromuinlistwhereu.age<30where!u.genderwhereu.occupation=="Doctor"selectu).Single(); /* C#版本2 */UseruserResult=list.Single(u=>u.age<30&&!u.gender&&u.occupation=="Doctor");
{id=6, name=LiuShuai, 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个人的姓名*/selectnamefromuserlimit3,3;
/* C#版本1 */List<string>nameList= (fromuinlistselectu.name).Skip(3).Take(3).ToList(); /* C#版本2 */List<string>nameList=list.Skip(3).Take(3).Select(x=>x.name).ToList();
LiuGuangzhi, LiuZiming, LiuShuai/* 输出结果 */
同理,Top(n)表示截取前n条数据。