C# LINQ查询详解(附带实例)
LINQ 全名为 Language Integrated Query,是 Microsoft 公司开发的语言集成查询,目前这项技术已经整合至 C# 语言。
过去我们学习数据库,如 SQL、XML文件、各种 Web 服务等时,必须针对每一种数据库学习查询语言,现在 Microsoft 公司将查询功能整合,设计了 LINQ,在这个架构下有相同的类、方法和事件。
因此可以使用 LINQ 技术同时应用在下列领域:
对于撰写数据库查询语言的程序设计师而言,LINQ 最明显的特色是使用声明式查询语法,通过使用查询语法,可以用最少的程序代码对数据来源进行排序、筛选或分组。当然其最大的特色是,相同的查询运算语法可以同时应用在 SQL 数据库、ADO.NET 数据集、XML 文件以及 .NET 集合中。
LINQ 已经是不同程序语言的共享技术,可以作为不同程序语言和不同数据库之间的桥梁,如下图所示。
【实例】 from 和 select 的基础应用,这个程序筛选出所有 arr 数组的内容,读者可以注意第 3 行,其使用 var 来声明查询结果变量 query。
where 可以搭配关系表达式来筛选数据。例如,扩充实例 1,增加 where,筛选小于 10 的数组内容。
假设现在要求读者筛选大于 5 且小于 15 的数据,这时需要使用 C# 的逻辑运算符“&&”,这将是读者的习题。where 可以搭配 bool 的条件式来筛选数据。
【实例】筛选偶数数据。
我们也可以将类数据用于筛选数据。例如,筛选主修是 CS(Computer Science) 的学生:
【实例】将句子拆解为单词,然后输出以 a、i、t 开头的单词。
【实例】 orderby 关键词的应用,第 3~8 行是执行从小到大排序,第 11~14 行是执行从大到小排序。
【实例】将 10 以下数字分奇数和偶数。
【实例】 join 方法的应用,这个程序会查询相同元素的内容。
【实例】 join 方法的应用,这个程序会列出 a 小于 5,b 大于 1,同时 a 等于 b 的结果。
【实例】 join 方法的应用,这个程序会进行姓名 (Name) 和学院 (College) 的配对。
过去我们学习数据库,如 SQL、XML文件、各种 Web 服务等时,必须针对每一种数据库学习查询语言,现在 Microsoft 公司将查询功能整合,设计了 LINQ,在这个架构下有相同的类、方法和事件。
因此可以使用 LINQ 技术同时应用在下列领域:
- LINQ to Objects:又称 LINQ to Collection,只要是属于 IEnumerable 或是 IEnumerable<T> 的集合都可以使用 LINQ 技术。
- LINQ to SQL:可以处理 SQL 数据库的数据。
- LINQ to XML:可以处理 XML 文件、XML 片段、XML 格式的字符串。
- LINQ to DataSet:可以处理 DataSet 中的数据。
对于撰写数据库查询语言的程序设计师而言,LINQ 最明显的特色是使用声明式查询语法,通过使用查询语法,可以用最少的程序代码对数据来源进行排序、筛选或分组。当然其最大的特色是,相同的查询运算语法可以同时应用在 SQL 数据库、ADO.NET 数据集、XML 文件以及 .NET 集合中。
LINQ 已经是不同程序语言的共享技术,可以作为不同程序语言和不同数据库之间的桥梁,如下图所示。

C# LINQ语法
LINQ 有 8 个基本表达式,可以参考下表:| 表达式 | 说明 |
|---|---|
| from | 指定查询操作的数据来源,和变量的范围 |
| select | 筛选查询结果的类型和形式 |
| where | 筛选的逻辑条件 |
| let | 在数据查询过程中,我们可以使用 let 关键词创建和存储子表达式的结果,未来可以使用子表达式的结果作为查询的依据 |
| orderby | 针对查询结果排序操作 |
| group ... by | 对查询结果分组,每个分组是一个数组,然后可以用 foreach 输出分组元素 |
| into | 创建临时标识符,用于存储 group、join、select 子句的执行结果 |
| join | 依据键值连接多个序列,返回查询的结果 |
1) from/select/where实例
使用 LINQ 习惯上会使用 var 来声明隐型变量,这可以简化设计,然后变量真正的数据类型由语句右边的类型决定,也就是在程序编译时决定数据类型。右边推断的类型可能是 C# 内建类型、匿名类型、使用者自定义的类型,或是 .NET 类库中定义的类型。【实例】 from 和 select 的基础应用,这个程序筛选出所有 arr 数组的内容,读者可以注意第 3 行,其使用 var 来声明查询结果变量 query。
int[] arr = new int[] { 1, 3, 5, 11, 21, 12, 6, 9, 20 };
var query = from n in arr select n;
foreach (var q in query)
Console.Write($"{q}, ");
执行结果为:
1, 3, 5, 11, 21, 12, 6, 9, 20,
where 可以搭配关系表达式来筛选数据。例如,扩充实例 1,增加 where,筛选小于 10 的数组内容。
int[] arr = new int[] { 1, 3, 5, 11, 21, 12, 6, 9, 20 };
var query = from n in arr
where n < 10 // 筛选 n < 10
select n;
foreach (var q in query)
Console.Write($"{q},");
执行结果为:
1,3,5,6,9,
假设现在要求读者筛选大于 5 且小于 15 的数据,这时需要使用 C# 的逻辑运算符“&&”,这将是读者的习题。where 可以搭配 bool 的条件式来筛选数据。
【实例】筛选偶数数据。
int[] arr = new int[] { 1, 3, 5, 11, 21, 12, 6, 9, 20 };
var query = from n in arr
where (n % 2 == 0) // 筛选偶数
select n;
foreach (var q in query)
Console.Write($"{q},");
执行结果为:
12,6,20,
我们也可以将类数据用于筛选数据。例如,筛选主修是 CS(Computer Science) 的学生:
var students = new List<Student>() {
new Student(){Id = 1, Name = "Mary", Major = "cs"},
new Student(){Id = 2, Name = "Tom", Major = "EE"},
new Student(){Id = 3, Name = "Sam", Major = "cs"},
new Student(){Id = 4, Name = "John", Major = "cs"}
};
// 查询所有主修是CS的学生
var query = from s in students
where s.Major == "cs"
select s;
// 输出结果
foreach (var q in query)
Console.WriteLine($"{q.Id}, {q.Name}");
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public string Major { get; set; }
}
执行结果为:
1, Mary
3, Sam
4, John
2) let实例
【实例】let 关键词的应用,这个程序会输出开头字母是 c~k 的英文单词。
var keywords = new[] {
"bool", "break", "byte",
"catch", "char", "delegate", "do", "double",
"else", "enum", "event", "explicit", "extern",
"false", "finally", "float", "for", "foreach",
"ref", "return", "short", "sizeof", "switch",
"this", "throw", "true", "try", "typeof",
"uint", "ulong", "ushort", "using",
"virtual", "void", "volatile", "while"
};
var query = from words in keywords
let firstLetter = words[0] // 取第1个字母
where firstLetter >= 'c' && firstLetter <= 'd'
select words;
foreach (var q in query)
Console.Write($"{q}, ");
执行结果为:
catch, char, delegate, do, double,
【实例】将句子拆解为单词,然后输出以 a、i、t 开头的单词。
string[] news = {
"Apple introduced Safety Check.",
"This robust security setting.",
"You may stop sharing your information."
};
// 将句子拆成单字数组,选择 'a'、'i'、't' 开头的单词
var query = from sentence in news
let words = sentence.Split(' ') // 拆解句子成单词数组
from word in words
let w = word.ToLower() // 单词转成全部小写
where w[0] == 'a' || w[0] == 'i' || w[0] == 't'
select word;
// 输出结果
foreach (var v in query)
Console.WriteLine($"{v} 是a、i、t开头单词");
执行结果为:
Apple 是a、i、t开头单词
introduced 是a、i、t开头单词
This 是a、i、t开头单词
information. 是a、i、t开头单词
3) orderby实例
使用 orderby 可以执行排序操作,默认是从小到大排序,使用关键词可以执行从大到小排序。【实例】 orderby 关键词的应用,第 3~8 行是执行从小到大排序,第 11~14 行是执行从大到小排序。
int[] arr = new int[] { 8, 3, 5, 11, 21, 12, 6, 9, 20 };
var query1 = from n in arr
where n < 10 // 筛选 n < 10
orderby n // 默认从小到大排序
select n;
foreach (var q in query1)
Console.Write($"{q}, ");
Console.WriteLine(); // 跳行输出
var query2 = from n in arr
where n < 10 // 筛选 n < 10
orderby n descending // 从大到小排序
select n;
foreach (var q in query2)
Console.Write($"{q}, ");
执行结果为:
3, 5, 6, 8, 9,
9, 8, 6, 5, 3,
4) group by实例
分组是 LINQ 强大的功能之一,可以执行下列分组策略:- 根据单一属性;
- 根据属性的第一个字母;
- 根据数字区间;
- 根据布尔值或其他表达式;
- 根据复合索引键。
【实例】将 10 以下数字分奇数和偶数。
int[] arr = new int[] { 8, 3, 5, 11, 21, 12, 6, 9, 20 };
var query = from n in arr
where n < 10 // 筛选 n < 10
group n by n % 2; // 分组奇数和偶数
foreach (var element in query) // 元素 element 是分组数组
{
foreach (var e in element) // 列出分组数组内容
Console.WriteLine(e);
Console.WriteLine("=====group组别分隔线=====");
}
执行结果为:
8
6
=====group组别分隔线=====
3
5
9
=====group组别分隔线=====
5) group by/into实例
当执行分组后,分组的键值可以用 Key 属性取得。例如,将 Student 类的数据依据科系主修分组。
var students = new List<Student>() {
new Student(){Id = 1, Name = "Mary", Major = "cs"},
new Student(){Id = 2, Name = "Tom", Major = "EE"},
new Student(){Id = 3, Name = "Sam", Major = "cs"},
new Student(){Id = 4, Name = "John", Major = "cs"},
new Student(){Id = 5, Name = "Kevin", Major = "EE"},
new Student(){Id = 6, Name = "Linda", Major = "cs"}
};
// 依科系分组
var query = from student in students
group student by student.Major into newGroup
select newGroup;
// 输出结果
foreach (var qGroup in query) {
Console.WriteLine($"科系:{qGroup.Key}"); // Key是分组属性
foreach (var student in qGroup) // 遍历分组
Console.WriteLine($"\t{student.Id}, {student.Name}");
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public string Major { get; set; }
}
执行结果为:
科系:cs
1, Mary
3, Sam
4, John
6, Linda
科系:EE
2, Tom
5, Kevin
6) join实例
关键词 join 用于连接数据,基本上需要外部序列 (outer sequence)、内部序列 (inner sequence)、键值 (key selector) 和结果选择,整个语法如下:from … in 外部序列 join … in 内部序列 on 外部键值 equals 内部键值 select
【实例】 join 方法的应用,这个程序会查询相同元素的内容。
int[] outer = new int[] { 1, 2, 3, 4, 5, 6, 7 };
int[] inner = new int[] { 1, 3, 4, 7 };
var query = from a in outer // 取得outer
join b in inner // 连接inner
on a equals b // 筛选元素 a = b
select b; // 筛选结果
foreach (var item in query)
Console.WriteLine(item);
执行结果为:
1
3
4
7
【实例】 join 方法的应用,这个程序会列出 a 小于 5,b 大于 1,同时 a 等于 b 的结果。
int[] outer = new int[] { 1, 2, 3, 4, 5, 6, 7 };
int[] inner = new int[] { 1, 3, 4, 7 };
var query = from a in outer // 取得outer
where a < 5 // 设定 a < 5
join b in inner // 连接inner
on a equals b // 筛选元素 a = b
where b > 1 // 设定 b > 1
select b; // 筛选结果
foreach (var item in query)
Console.WriteLine(item);
执行结果为:
3
4
【实例】 join 方法的应用,这个程序会进行姓名 (Name) 和学院 (College) 的配对。
IList<Student> studentList = new List<Student>() {
new Student(){ID = 1, Name = "Tom", Major = "CS"},
new Student(){ID = 2, Name = "Kevin", Major = "ME"},
new Student(){ID = 3, Name = "Bill", Major = "History"},
new Student(){ID = 4, Name = "Jonny", Major = "Language"},
new Student(){ID = 5, Name = "Mike", Major = "cs"}
};
IList<School> schoolList = new List<School>() {
new School(){Major = "cs", College = "abc"},
new School(){Major = "ME", College = "abc"},
new School(){Major = "MBA", College = "Business"}
};
var query = from s in studentList // outer
join st in schoolList // inner
on s.Major equals st.Major // 筛选科系相同
select new {
name = s.Name, // 姓名
major = s.Major, // 主修
college = st.College // 学院
};
foreach (var q in query)
Console.WriteLine($"{q.name} 就读 {q.college} 学院主修是 {q.major}");
public class Student {
public int ID { get; set; }
public string Name { get; set; }
public string Major { get; set; }
}
public class School {
public string Major { get; set; }
public string College { get; set; }
}
执行结果为:
Tom 就读 abc 学院主修是 CS
Kevin 就读 abc 学院主修是 ME
Mike 就读 abc 学院主修是 cs
ICP备案:
公安联网备案: