LINQ查询技术
LINQ(Language Integrated Query)是一种C#语言中的查询技术,它允许我们在代码中使用类似SQL的查询语句来操作各种数据源。这些数据源可以是集合、数组、数据库、XML文档等等。LINQ提供了一种统一的编程模型,使我们能够使用相同的方式来查询和操作不同类型的数据。
在C#中,LINQ主要由以下几个组成部分:
数据源(Data source):可以是集合、数组、数据库、XML文档等等。
查询变量(Query variable):用于存储查询结果的变量。
查询表达式(Query expression):类似于SQL语句的查询表达式,用于描述查询的逻辑和条件。
查询操作符(Query operator):用于执行各种查询操作,如筛选、排序、分组、投影等等。
查询结果(Query result):查询操作的返回结果。
其中数据源,查询变量,查询结果是必选项,查询表达式,查询操作符是可选项。
分类
LINQ To Entities:查询实体(数据集)
LINQ To Objects:查询对象
LINQ To XML
IQueryable能被查询 AsQueryable() 把 DbSet 转换成IQueryable
LINQ 语法
LINQ 有两种主要的语法:
- 查询表达式(Query Syntax):类似 SQL 语法
- 方法语法(Method Syntax):使用扩展方法,如
.Where()
、.Select()
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 查询表达式
var evenNumbersQuery =
from num in numbers //forom: 从哪里查(num 查询变量) in: 在哪个数据源中(numbers 数据源)
where num > 3 && num < 9 //查询条件
select num; //查询结果(是一个集合)
// 方法语法
var evenNumbersMethod = numbers.Where(num => num % 2 == 0);
Console.WriteLine("偶数(查询表达式): " + string.Join(", ", evenNumbersQuery));
Console.WriteLine("偶数(方法语法): " + string.Join(", ", evenNumbersMethod));
}
}
多个数据源:
var evenNumbersQuery =
from num in numbers
form s in student
where s > 3 && s < 9
select s;
//多个数据源后面的数据源可以使用前面的数据源的数据
常用方法
1. 筛选与过滤
-
Where:筛选满足条件的元素。
int[] numbers = { 1, 2, 3, 4, 5 }; var evens = numbers.Where(n => n % 2 == 0); // 结果:2, 4
-
OfType:筛选特定类型的元素(常用于混合类型集合)。
object[] mixed = { 1, "two", 3, "four" }; var strings = mixed.OfType<string>(); // 结果:two, four
2. 投影与转换
-
Select:将元素转换为新形式。
string[] words = { "apple", "banana" }; var upper = words.Select(w => w.ToUpper()); // 结果:APPLE, BANANA
-
SelectMany:将嵌套集合展平为一维集合。
List<string[]> groups = new List<string[]> { new[] { "a", "b" }, new[] { "c" } }; var flat = groups.SelectMany(g => g); // 结果:a, b, c
3. 排序
-
OrderBy:按升序排序。
int[] numbers = { 3, 1, 4, 2 }; var sorted = numbers.OrderBy(n => n); // 结果:1, 2, 3, 4 //方法2. var evenNumbersQuery = from num in numbers Orderby num ascending //升序(默认可以省略) select num;
-
OrderByDescending:按降序排序。
var desc = numbers.OrderByDescending(n => n); // 结果:4, 3, 2, 1 //方法2. var evenNumbersQuery = from num in numbers Orderby num descending //降序 select num;
-
ThenBy:在已有排序基础上进行次级排序。
var students = new[] { new { Name = "Bob", Age = 20 }, new { Name = "Alice", Age = 20 } }; var ordered = students.OrderBy(s => s.Age).ThenBy(s => s.Name); // 先按年龄,再按姓名
4. 分组
-
GroupBy:按键将元素分组。
string[] words = { "cat", "dog", "car" }; var grouped = words.GroupBy(w => w[0]); // 按首字母分组:c -> {cat, car}, d -> {dog} //方法2.查询表达式 var grouped = from s in c.Students group s by s.ClassId into g //orderby g.Key select new { classId = g.Key, count = g.Count() };
5. 聚合(计算)
-
Count:计算元素个数。
int[] numbers = { 1, 2, 3 }; var count = numbers.Count(); // 结果:3
-
Sum:计算总和。
var sum = numbers.Sum(); // 结果:6
-
Max/ Min:查找最大/最小值。
var max = numbers.Max(); // 结果:3 var min = numbers.Min(); // 结果:1
-
Average:计算平均值。
var avg = numbers.Average(); // 结果:2
-
Aggregate:自定义聚合操作。
var result = numbers.Aggregate((a, b) => a * b); // 结果:1 * 2 * 3 = 6
6. 集合操作
-
Distinct:移除重复元素。
int[] numbers = { 1, 2, 2, 3 }; var unique = numbers.Distinct(); // 结果:1, 2, 3
-
Union:合并两个集合并去重。
int[] a = { 1, 2 }, b = { 2, 3 }; var union = a.Union(b); // 结果:1, 2, 3
-
Intersect:返回两个集合的交集。
var intersect = a.Intersect(b); // 结果:2
-
Except:返回集合A中不在B中的元素。
var except = a.Except(b); // 结果:1
-
Join:关联
//方法1. var result = collectionA.Join(collectionB, a => a.Key, b => b.Key, (a, b) => new { a, b }); //方法2. var query = from s in c.Students join cr in c.ClassRooms on s.ClassId equals cr.Id join u in c.Users on s.CreateUserId equals u.Id join u2 in c.Users on s.LastUpdateUserId equals u2.Id into result // 把关联的结果存储到result中 from item in result.DefaultIfEmpty() // 表中找不到匹配项,则item6为空null,这样就不会因为匹配不到数据而丢失该条借阅记录。
7. 分页与元素选择
综合下面方法,使用分页:
int pageSize = 10; // 每页10条
int pageNumber = 1; // 第1页
var pagedUsers = users
.OrderBy(u => u.Id) //排序
.Skip((pageNumber - 1) * pageSize) //跳过前面页的数据
.Take(pageSize) //取出当前页的数据
.ToList(); //转换为列表
-
Take:取前N个元素。
int[] numbers = { 1, 2, 3, 4 }; var top3 = numbers.Take(3); // 结果:1, 2, 3
-
Skip:跳过前N个元素。
- Skip 使用前必须先排序 numbers.OrderByDescending.Skip
var skip2 = numbers.Skip(2); // 结果:3, 4
- First/ FirstOrDefault<font color='MediumSeaGreen'>:返回第一个元素(后者在空集合时返回默认值)。</font>
```csharp
var first = numbers.First(); // 结果:1
var empty = new int[] {}.FirstOrDefault(); // 结果:0
-
Last/ LastOrDefault:返回最后一个元素。
var last = numbers.Last(); // 结果:4
-
Single/ SingleOrDefault:返回唯一元素(若有多个则抛异常)。
int[] single = { 1 }; var one = single.Single(); // 结果:1
8. 判断与检查
-
Any:检查是否至少有一个元素满足条件。
int[] numbers = { 1, 2, 3 }; var hasEven = numbers.Any(n => n % 2 == 0); // 结果:true
-
All:检查是否所有元素都满足条件。
var allPositive = numbers.All(n => n > 0); // 结果:true
-
Contains:检查集合是否包含某元素。
var has2 = numbers.Contains(2); // 结果:true
9. 执行与转换
-
ToList:将查询结果转换为List
<T>
并立即执行。var list = numbers.Where(n => n > 2).ToList(); // 结果:List {3}
-
ToArray:转换为数组。
var array = numbers.ToArray(); // 结果:int[] {1, 2, 3}
-
ToDictionary:转换为字典。
var dict = students.ToDictionary(s => s.Name, s => s.Score); // 结果:{ "Alice": 85, "Bob": 92 }
10. 其他实用方法
-
Concat:连接两个序列。
int[] a = { 1, 2 }, b = { 3, 4 }; var combined = a.Concat(b); // 结果:1, 2, 3, 4
-
Reverse:反转序列。
var reversed = numbers.Reverse(); // 结果:3, 2, 1
-
Zip:将两个序列按位置配对。
int[] nums = { 1, 2 }, chars = { 'a', 'b' }; var pairs = nums.Zip(chars, (n, c) => $"{n}{c}"); // 结果:1a, 2b