LINQ
#.NET
2024-10-03
什么是LINQ
LINQ(Language-Integrated Query,语言集成查询)是微软在 .NET 框架中引入的一种数据查询方法。它允许开发者使用类似于 SQL 的语法,在编程语言(如 C#、VB.NET)中直接对各种数据源(如集合、数据库、XML 等)进行查询操作。LINQ 的主要优势在于其统一的查询语法和与编程语言的紧密集成,使得数据操作更加简洁、类型安全且易于维护。
LINQ 的主要组成部分
LINQ 支持查询不同类型的数据源,主要包括以下几个部分:
LINQ to Objects
- 功能:用于对内存中的对象集合(如
List<T>
、Array
、Dictionary<T>
等)进行查询和操作。它不需要任何外部资源,完全基于 .NET 集合框架。 - 使用场景:当你有内存中的数据,如通过计算生成的数据或从文件中读取的数据时,使用 LINQ to Objects 进行过滤、排序、分组等操作非常方便。
- 示例:
1
2
3
4
5
6
7List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 查询所有偶数
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
// 使用方法链语法
var evenNumbersMethod = numbers.Where(num => num % 2 == 0).ToList();
- 功能:用于对内存中的对象集合(如
LINQ to SQL
- 功能:用于查询 SQL Server 数据库,将数据库表映射为 .NET 类,允许使用 LINQ 语法执行查询操作。它的目标是让开发者用更直观的面向对象方式与数据库进行交互,而不是通过 SQL 字符串。
- 使用场景:当你想要访问 SQL Server 数据库并进行 CRUD 操作时,可以使用 LINQ to SQL。你可以将数据库中的表与 .NET 对象一一映射,通过查询表达式来操作数据。
- 示例:
1
2
3
4
5
6
7
8
9using (var db = new DataContext())
{
// 查询来自 "Customers" 表的所有北京的客户
var beijingCustomers = from customer in db.GetTable<Customer>()
where customer.City == "Beijing"
select customer;
// 或者使用方法链语法
var beijingCustomersMethod = db.GetTable<Customer>().Where(c => c.City == "Beijing").ToList();
}
LINQ to XML
- 功能:用于处理 XML 数据,提供了一种方便的方式来查询、创建和修改 XML 文档。它与传统的
System.Xml
类库不同,更加简洁、直观。 - 使用场景:当你需要读取、查询或生成 XML 数据时,LINQ to XML 是一种强大的工具。它可以在应用程序中动态解析和处理 XML 数据。
- 示例:
1
2
3
4
5
6
7
8// 读取并查询 XML 文件
XDocument doc = XDocument.Load("books.xml");
var books = from book in doc.Descendants("book")
where (string)book.Element("author") == "J.K. Rowling"
select book;
// 使用方法链语法
var booksMethod = doc.Descendants("book").Where(b => (string)b.Element("author") == "J.K. Rowling");
- 功能:用于处理 XML 数据,提供了一种方便的方式来查询、创建和修改 XML 文档。它与传统的
LINQ to Entities(Entity Framework)
- 功能:基于 Entity Framework(EF)的 LINQ 查询方式,通过 ORM(对象关系映射)技术将数据库中的表映射为实体类,使得开发者可以使用 LINQ 对数据库进行查询和操作。LINQ to Entities 是 LINQ to SQL 的一个升级版,支持更多的数据库(不仅仅是 SQL Server)。
- 使用场景:当你使用 Entity Framework 时,LINQ to Entities 可以让你通过实体类来查询数据库,而不需要直接编写 SQL 语句。
- 示例:
1
2
3
4
5
6
7
8
9
10using (var context = new MyDbContext())
{
// 查询价格大于 100 的所有产品
var expensiveProducts = from product in context.Products
where product.Price > 100
select product;
// 使用方法链语法
var expensiveProductsMethod = context.Products.Where(p => p.Price > 100).ToList();
}
LINQ to DataSet
- 功能:用于查询
DataSet
或DataTable
对象,它们通常从数据库或 XML 文件中填充数据。LINQ to DataSet 提供了一种方便的方法来查询 ADO.NET 数据结构。 - 使用场景:当你使用传统的 ADO.NET 数据集和表结构时,LINQ to DataSet 可以让你用类似 SQL 的语法查询这些结构,而不必手动遍历行。
- 示例:
1
2
3
4DataSet ds = GetDataSet(); // 假设已经有数据集
var products = from product in ds.Tables["Products"].AsEnumerable()
where product.Field<decimal>("Price") > 100
select product;
- 功能:用于查询
LINQ 的语法形式
LINQ 提供了两种主要的查询语法,每种都有其独特的用途:
查询表达式语法(Query Expression Syntax):
- 描述:它是一种类 SQL 的语法,开发者使用
from
,where
,select
,group by
,orderby
等关键字来编写查询表达式。这种语法更加接近自然语言,特别适合熟悉 SQL 的开发者。 - 优势:当你需要处理复杂的查询时,如分组、连接等,查询表达式语法会让代码更易读、更直观。
- 例子:
1
2
3
4
5
6
7
8
9
10
11var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 查询所有偶数
var evenNumbers = from num in numbers
where num % 2 == 0
select num;
foreach (var number in evenNumbers)
{
Console.WriteLine(number); // 输出 2, 4, 6
}
- 描述:它是一种类 SQL 的语法,开发者使用
方法链语法(Method Syntax 或 Fluent Syntax):
- 描述:这种语法基于扩展方法(即集合类上的
.Where()
、.Select()
等方法),可以通过链式调用来构建查询。它通常更加灵活,适合函数式编程风格。 - 优势:方法链语法在处理简单查询时十分高效,且与 .NET 的其他函数式编程方法(如
lambda 表达式
)结合使用时非常强大。 - 例子:
1
2
3
4
5
6
7
8
9var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 使用方法链语法查询所有偶数
var evenNumbers = numbers.Where(num => num % 2 == 0);
foreach (var number in evenNumbers)
{
Console.WriteLine(number); // 输出 2, 4, 6
}
- 描述:这种语法基于扩展方法(即集合类上的
查询表达式语法和方法链语法的对比
特点 | 查询表达式语法 | 方法链语法 |
---|---|---|
语法风格 | 类 SQL | 函数式编程 |
适合场景 | 复杂查询(分组、连接、嵌套查询) | 简单、灵活的查询(过滤、投影等) |
代码可读性 | 类似自然语言,易于理解 | 更简洁,但对于复杂查询的可读性可能较差 |
表达的灵活性 | 稍微不如方法链灵活,某些高级操作需要转为方法链 | 灵活,支持所有扩展方法、lambda 表达式等 |
学习难度 | 熟悉 SQL 的人容易上手 | 需要掌握扩展方法和 lambda 表达式 |
常用的 LINQ 操作符
- Where:筛选集合中的元素。
1
var result = numbers.Where(n => n % 2 == 0);
- Select:投影(映射)操作,返回新的集合。
1
var squares = numbers.Select(n => n * n);
- OrderBy/OrderByDescending:排序。
1
var ordered = numbers.OrderBy(n => n);
- GroupBy:对集合分组。
1
var groups = numbers.GroupBy(n => n % 2);
- Join:连接两个集合。
1
2
3var result = from c in customers
join o in orders on c.CustomerId equals o.CustomerId
select new { c.Name, o.OrderDate };