LINQ

LINQ(Language Integrated Query)读作[lɪŋk],是一种用于.Net平台的查询语言集成技术,它能够允许开发人员用类似SQL结构化查询的语法来查询和操作数据源,这里的数据源包括对象集合、XML文档、数据库等。LINQ支持C#和VB.NET,C#中使用LINQ的主要目的是简化查询数据逻辑的写法,提高代码的可读性和可维护性。

下面我们直接看一个LINQ的使用例子,代码中我们查询长度为4的所有字符串。

List<string> data = new List<string> { "Tom", "Jerry", "Kate", "Lucy", "Bob" };
// 使用LINQ查询长度为4的字符串
IEnumerable<string> result = from s in data where s.Length == 4 select s;
// 输出查询结果
foreach (var s in result)
{
    Console.WriteLine(s);
}

有人可能觉得上面例子其实不用LINQ也很容易实现,毕竟迭代判断也不复杂。实际上,LINQ其实体现了一种结构化查询的思想,这和在关系型数据库中,我们使用SQL语言的理由是一样的。如果集合元素是个复杂的对象,而且有多个集合「关联查询」的情况,LINQ的优势就体现出来了。

LINQ相关概念

LINQ Provider

我们能够使用LINQ从某个数据源中查询数据,其实是被查询的数据源将自身实现为了LINQ提供者程序(LINQ Provider)。.Net Framework和.Net Core中提供了一些默认的LINQ Provider,常见的包括:

LINQ To Objects:最常用的LINQ Provider之一,用于从对象集合中查询数据。

LINQ To XML:用于使用LINQ语法查询和操作XML文档。

LINQ To SQL:用于和关系型数据库交互,允许开发者用LINQ语法来查询数据库中的数据,后来该LINQ Provider被EFCore框架取代。

除此之外,我们也可以实现自定义的LINQ Provider。

方法语法 vs 查询语法

LINQ在C#中有两种主要的语法风格:方法语法查询语法

方法语法使用类似于函数调用的方式来执行LINQ查询,代码中我们需要使用一系列LINQ扩展方法来构建和链式组合查询操作,下面是使用方法语法查询数据的例子。

List<string> data = new List<string> { "Tom", "Jerry", "Kate", "Lucy", "Bob" };
IEnumerable<string> result = data.Where(s => s.Length == 4);

查询语法更像完整的SQL语句,我们需要在LINQ中使用fromwhereselect等关键字描述查询操作,下面是使用查询语法查询数据的例子。

List<string> data = new List<string> { "Tom", "Jerry", "Kate", "Lucy", "Bob" };
IEnumerable<string> result = from s in data where s.Length == 4 select s;

上面例子中,方法语法和查询语法是等效的,无论使用哪种风格都可以达到相同的查询目的。方法语法通常更紧凑,适合链式操作;而查询语法更类似SQL语句,对于某些人来说可读性更好。实际开发中,我们应该根据实际情况进行选择。

LINQ查询结果

LINQ查询可能返回不同类型的查询结果,这取决于具体的查询操作和想要呈现结果的方式(投影)。

IEnumerable:这是LINQ查询最常见的结果类型,表示包含查询结果的可迭代集合。下面例子代码查询了Age属性等于18的对象集合。

List<Student> data = new List<Student>
{
    new Student { Name = "Tom", Age = 18 },
    new Student { Name = "Lucy", Age = 17 },
    new Student { Name = "Bob", Age = 18 }
};
IEnumerable<Student> result = from s in data where s.Age == 18 select s;

匿名类型:LINQ查询可返回匿名类型,这是一种临时的没有明确类名的类型,通常用于临时投影查询结果。

List<Student> data = new List<Student>
{
    new Student { Name = "Tom", Age = 18 },
    new Student { Name = "Lucy", Age = 17 },
    new Student { Name = "Bob", Age = 18 }
};
var result = from s in data where s.Age == 18 select new { Name = s.Name, Age = s.Age };

注意:匿名类型变量由于没有具体的类型名,我们通常使用var声明。

单个值类型:对于一些聚合查询或是查询单个元素等情况,LINQ可能会返回单个值而不是集合。

List<Student> data = new List<Student>
{
    new Student { Name = "Tom", Age = 18 },
    new Student { Name = "Lucy", Age = 17 },
    new Student { Name = "Bob", Age = 18 }
};
double avg = data.Average(s => s.Age);

LINQ查询表达式

from子句

from子句指定了作为数据源使用的数据集合和迭代变量。

from Type d in data

其中的Type类型可以省略不写,实际开发中一般都将其省略。from子句可以有任意个,等价为多层循环,下面是一个例子。

List<int> data1 = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
List<int> data2 = new List<int> { 2, 4, 6, 8, 10 };
var result = from d1 in data1
    from d2 in data2
    where d1 > 3 && d2 > 6
    select new { D1 = d1, D2 = d2 };

上面代码的计算结果为:

{ D1 = 4, D2 = 8 }
{ D1 = 4, D2 = 10 }
{ D1 = 5, D2 = 8 }
{ D1 = 5, D2 = 10 }
{ D1 = 6, D2 = 8 }
{ D1 = 6, D2 = 10 }
{ D1 = 7, D2 = 8 }
{ D1 = 7, D2 = 10 }

join子句

join子句用于连接两个集合创建一个新的集合,from子句后可以有任意个join子句来生成连接集合。

from Type d1 in data1 join Type d2 in data2 on join条件

类似from子句,其中的Type类型都可以省略不写。

List<Student> students = new List<Student>
{
    new Student { Name = "Tom", Age = 18, CourseId = 1 },
    new Student { Name = "Lucy", Age = 17, CourseId = 1 },
    new Student { Name = "Bob", Age = 18, CourseId = 2 }
};
List<Course> courses = new List<Course>()
{
    new Course() { CourseId = 1, Name = "数学" },
    new Course() { CourseId = 2, Name = "语文" }
};
IEnumerable<Student> result = from student in students
    join course in courses on student.CourseId equals course.CourseId
    where course.Name == "数学"
    select student;

let子句

let子句接收一个运算表达式并将其赋值给一个标识符,下面是一个例子。

List<int> data1 = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
List<int> data2 = new List<int> { 2, 4, 6, 8, 10 };
IEnumerable<int> result = from d1 in data1
    from d2 in data2
    let sum = d1 + d2
    where sum > 5
    select sum;

where子句

where子句需要指定筛选条件,LINQ根据该条件来筛选结果数据。where子句可以有多个,它们是AND关系,然而我们一般不会这样写,而是在一个where子句中使用&&连接多个条件。

上面代码中我们已经使用过很多次where子句了,这里就不单独编写例子了。

orderby子句

orderby子句用于对查询结果进行排序。

List<int> data = new List<int> { 7, 6, 5, 4, 3, 2, 1 };
IEnumerable<int> result = from d in data orderby d ascending select d;

orderby子句中我们可以使用ascendingdescending指定升序或降序。

groupby子句

groupby子句用于对查询结果进行分组,它可以看作一个包含分组功能的select子句。

List<Student> students = new List<Student>
{
    new Student { Name = "Tom", Age = 18, CourseId = 1 },
    new Student { Name = "Lucy", Age = 17, CourseId = 1 },
    new Student { Name = "Bob", Age = 18, CourseId = 2 }
};
IEnumerable<IGrouping<int, Student>> result = from student in students
    group student by student.CourseId;
foreach (var group in result)
{
    foreach (var d in group)
    {
        Console.WriteLine("{0} {1} {2}", group.Key, d.Name, d.Age);
    }
}

上面代码的计算结果为:

1 Tom 18
1 Lucy 17
2 Bob 18
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap