学编程,来源栈;先学习,再交钱
当前系列: C#语法 修改讲义

类SQL写法

除了可以用我们之前学习的Linq方法,还可以使用Linq查询表达式:

            var excellent = from s in students
                            select s;
这是一种类似于(数据库查询语言)SQL的写法。推出这种书写方法,应该是为了照顾SQL开发人员,或者暗示/表明Linq是可以“代替”SQL的。

但C#编译器实际上会把所有的Linq查询表达式都编译成Linq方法,然后执行。

语法说明:
  • 以 from 开头,后接开发人员自定义的命名,代表集合中的元素
  • in后面的数据源(source data)必须是IEnumerable
  • 必须以select(或 group)结尾,可以把select理解为“返回(return)”
  • 查询(query)结果仍然是IEnumerable的


where

只要where后面的表达式返回的是bool值就行:

var excellent = from s in students
                //where s.Majors.Count > 2
                //where s.Majors.Contains(csharp)
                //where !s.Majors.Contains(Javascript)
                where s.Name.StartsWith('王') && s.Score > 80
                select s;


orderby

默认升序:

var excellent = from s in students
                //orderby s.Score 默认升序(ascending)
                orderby s.Score descending
                select s;

还可以先按某字段升/降序,再按另一字段升降序(同ThenBy())

var excellent = from s in students
                orderby s.Score ascending, s.Name descending
                select s;

orderby和where可以组合使用:

var excellent = from s in students
                where s.Score > 80
                orderby s.Score ascending, s.Name descending
                select s;


select

从原有结果集中取出或增加若干属性重新组合成新的集合。比如:

var excellent = from s in students
                select s.Name;

多属性组合的,可以使用预设类

select new Score { Name = s.Name, Value = s.Score };

也使用匿名对象:

select new { s.Name, s.Score };


group

majors按Teacher分组,结果可以直接返回:

var result = from m in majors
            group m by m.Teacher //关键字:group 、by 

需要多个属性进行分组的时候:

var result = from m in majors
                group m by new { m.Teacher, m.Age }  //使用匿名对象
还可以对分组结果集再运算(统计)
var result = from m in majors
            group m by m.Teacher 
            into gm     //into类似于命名,将之前的结果集命名为:gm
            select new  //利用投影
            {
                gm.Key, //老师的名字
                Count = gm.Count()    //聚合运算
            };


join

在majors和teachers之间用老师的姓名join:

var result = from m in majors
            join t in teachers
            on m.Teacher equals t.Name
            select m;

语法要点:进行关联时,

  • on后面,用的不是==,而是专用关键字equals
  • equals左右两边是有顺序的,只能是先m再t
此外,多个字段组成的连接条件,使用匿名类(调整数据源,设定两个不同年龄的飞哥):
on new { Name = m.Teacher, m.Age } equals new { t.Name, t.Age }
结果还可以投影:
select new 
{ 
    MajorName = m.Name, 
    TeacherName = t.Name,
    t.Age
};
还可以继续join,关联多个集合:
var result = from m in majors
            join t in teachers
            on new { Name = m.Teacher, m.Age } equals new { t.Name, t.Age }
            join s in students
            on m.Name equals s.Name
还可以在结果中过滤
where t.Name == "小鱼"

outer join

其实上面(默认)的join,又被称之为inner join,其特点是只会返回完全满足join条件的集合元素。

与之相对的,还有(left)outer join,即:所有左边的(第一个)集合元素都必须返回,哪怕在右边的(第二个)集合无法匹配到(无法匹配就显示为null)。

为了演示效果,添加一个CSS的Major:

Major Css = new Major { Name = "CSS" };

不要忘了将其添加到集合:

IEnumerable<Major> majors = new List<Major> { csharp, SQL, Javascript, UI, Css };

PS:Linq中只有left join,没有right join 

在Linq中需要使用DefaultIfEmpty()方法实现outer join的效果:

var result = from m in majors    //major放在前面,表示所有的major都要呈现
                join t in teachers
                on m.Teacher equals t.Name
                into mt             //又见into,mt代表的是teachers
                                    //调用了DefaultIfEmpty()并再次from
                from joined in mt.DefaultIfEmpty()
                select new
                {
                    MajorName = m.Name,
                    TeacherName = joined?.Name ?? "没有老师",
                    TeacherAge = joined?.Age ?? 0
                };

复习:null值的处理

#试一试#:如果我们想要(以teachers为基准返回所有的teacher元素,应该如何join?

cross join

左右两边的集合进行无条件的多对多交叉连接(执行笛卡尔乘积),使用多个from实现
var result = from t in teachers
                from m in majors
                select new {  t, m };

实际上,inner join和outer join都是在cross join的基础上进行过滤,比如我们加这么一个条件:

where t.Name == m.Teacher
结果就变成了inner join。(另:无论何种join,都是可以join之后继续where过滤的)


let子句

对应SelectMany()方法:

var result = from s in students
            let ms = s.Majors   //把所有的 Major 先暴露出来
            from m in ms        //后面就可以使用 let 指定的 ms
            select new { student = s.Name, major = m.Name };

一样添加where条件

where m.Name.ToLower().Contains("s")


混用

查询表达式和方法,是可以的。比如:

var result = from s in students.Where(x => x.Score > 80)
或者:
result = result.OrderByDescending(r => r.student.Score);

注意:不要忘记使用返回值赋值!



作业

见:J&C:集合概述 / 迭代器模式 / ER模型 / 仓储模式,注意用Linq表达式实现

学习笔记
源栈学历
今天学习不努力,明天努力找工作

作业

觉得很 ,不要忘记分享哟!

任何问题,都可以直接加 QQ群:273534701

在当前系列 C#语法 中继续学习:

多快好省!前端后端,线上线下,名师精讲

  • 先学习,后付费;
  • 不满意,不要钱。
  • 编程培训班,我就选源栈

更多了解 加:

QQ群:273534701

答疑解惑,远程debug……

B站 源栈-小九 的直播间

写代码要保持微笑 (๑•̀ㅂ•́)و✧

公众号:源栈一起帮

二维码