原文起始连接:https://dotnettutorials.net/course/linq/
说明:这篇文章标题比较难起,归类也挺麻烦。关于Linq的知识,dotnettutorial网站用一系列的文章来讲解。每一篇都翻译的话,量还是比较大的。所以我计划先看,再整理翻译。
Linq简介
简介
LINQ(Language Integrated Query),语言集成查询。.NET Framework3.5
和C# 3.0
一同发行。提供通用查询语法来支持不同数据源,包括内存中的数据、数据库数据(SQL、Oracle等)、XML文档等。如果没有Linq,那么你需要根据数据源的不同,学习不同的查询语法来支持数据查询工作。
Linq提供者(Provider),通过实现IQueryProvider和IQueryable接口来实现具体数据源数。而程序开发人员只需要针对Linq提供者提供的数据查询即可,可以像使用对象一样来编写查询。
例子
Linq语句包含三个部分:
- 初始化: 确定数据源
- 条件:where、过滤、排序等
- 查询:单独查询、分组查询、联合查询等
Linq语句的三种书写方式:
1 | //准备数据源(内存中的数组) |
优点:
- 无需为新的数据源学习新的查询语言语法
- 精简代码
- 编译时检查错误
- 提供内置方法方便实现查询、排序、分组等
- 查询是可复用的
缺点
- 很难写出复杂的SQL查询
- 并没有实现所有的SQL功能,比如存储过程
- 如果查询编写的不好,性能将会非常差
- 修改查询,则需要重新部署应用,重新发布dll至服务器
IEnumerable与IQueryable
IEnumerable在System.Collection命名空间下,它只有一个GetEnumerator()方法。该方法的定义如下(泛型和非泛型)
1 | public interface IEnumerable |
IQueryable在System.Linq命名空间下,继承自IEnumerable接口。因此我们可以把一个IQueryable的变量赋值给IEnumerable变量。IQueryable接口有一个IQueryProvider成员。
1 | namespace System.Linq |
总结:
IEnumerable
- 在System.Collections命名空间下的接口
- 从数据库查询数据时,IEnumerable在服务端(数据库)执行seelct语句。数据加载到客户端内存中,然后在内存中的数据获取需要的(执行条件过滤)
- 当需要查询内存中数据(List、Array等)要使用IEnumerable接口
- 大多用于LINQ to Object 和LINQ to XML查询
- IEnumerable只能向前获取数据,不能往后或截取片段
- 不支持自定义查询
- 不支持懒加载,因此不支持分页场景
Enumerable类中也有Where方法的实现,该方法定义如下:1
IEnumerable<TSource> Where<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate);
IQueryable
- 在System.Linq命名空间下的接口
- 从数据库查询数据时,IQueryable在服务端(数据库)执行带过滤的查询语句,然后获取需要的数据
- 当需要获取非内存数据(如远端数据库)时使用IQueryable接口
- 通常用于LINQ to SQL 和LINQ to Entities查询
- 类型集合只能往前,不能往后或截取片段
- 支持延迟执行
- 通过CreateQuery和Executes方法来支持自定义查询
- 支持延迟加载(lazy loading),支持分页场景
查看Where方法定义如下,它是IQueryable接口的一个扩展方法
1 | public static IQeueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Func<TSource, bool> predicate) |
关于何时使用IEnumerable和IQueryable,在之前的文章中也有过讨论,戳这里
扩展方法
C#的扩展方法允许我们在不改变已有类的代码前提下,向该类添加一个方法。具体做法是定义一个静态类,该静态类下实现一个静态方法,方法的第一个参数需要使用this关键字。举个例子,在string类中添加一个方法获取字符串中单词的个数。
1 | public static class StringExtension |
此时,我们在项目中定义的string类型变量,就可以直接以.GetWordCount()
方式调用这个方法了。因为这是一个静态方法,当然也可以使用类名.方法名()
的方式来调用。
1 | //扩展方法调用 |
Enumerable.cs类中实现了许多扩展方法如Where、Join等,既然是扩展方法,调用方式就有上面两种。
1 | List<int> intList = new List<int>() |
LINQ查询操作符
LINQ操作符就是一系列的扩展方法用来写LINQ查询。
查询操作符(Select):用来投影(Projection),从数据源中查询数据的机制。你可以按数据源原样查询出,也可以创建自己的结果形式。下面举例仅引用一些原文的图片,代码片段有点长,后期考虑github上建个repo。
下面两条语句将Employee对象原样查询出来
下面两条语句构建一个新的数据对象,不包含ID字段
下面两条语句构建一个新的数据匿名对象
下面两条语句创建带有索引值的对象
SelectMany查询,用于合并一系列的结果成为一个。下面看个例子:
1 | static void Main(string[] args) |
另外一个例子
1 | var methodSyntax = Student.GetStudents() |
- 本文作者: 达文西
- 本文链接: https://edsiongithub.github.io/2022/03/28/0038/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!