LINQ入门简介

一.什么是LINQ

LINQ是 .NET 3.0 版中引入的一项创新功能。LINQ(读音link)表示语言集成查询(Language Integrated Query),是.NET框架的扩展,它允许我们用SQL查询数据库的方式来查询数据的集合,使用它,你可以使用统一的方式从数据库、程序对象的集合以及XML文档中查询数据.

二.为什么要使用LINQ

要理解为什么使用LINQ,先来看下面一个例子。“假设有一个整数类型的数组,找到里面的偶数并进行降序排序。”

在C#3.0以前,如果要实现这样的功能,我们必须使用’foreach’或’for’循环来遍历数组,先找到偶数然后在降序排序,相关代码如下:

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        // 查询出数组中的偶数并排序
        int[] ints = {
    
     5, 2, 0, 66, 4, 32, 7, 1 };
        // 定义一个整数类型的集合,用来存放数组中的偶数
        List<int> list = new List<int>();
        // 遍历数组查询出偶数放到集合中
        foreach (int i in ints)
        {
    
    
            // 如果是偶数,把偶数加入到集合中
            if (i % 2 == 0) list.Add(i);
        }

        // 正序排序
        list.Sort();
        // 反转
        list.Reverse();
        // 输出
        Console.WriteLine(string.Join(",",list));
    }
}

C#3.0之后引入了新特性LINQ,下面的示例演示了如何使用LINQ来查询数组,示例代码如下:

class Program
{
    
    
    static void Main(string[] args)
    {
    
    
        // 查询出数组中的奇数并排序
        int[] ints = {
    
     5, 2, 0, 66, 4, 32, 7, 1 };
        // 使用LINQ和Lambda表达式查询数组中的偶数
        int[] intEvens= ints.Where(p => p % 2 == 0).ToArray();

        // 输出
        Console.WriteLine("偶数:" + string.Join(",", intEvens));
        Console.WriteLine("奇数:" + string.Join(",", intOdds));
    }
}

在上面的例子中可以看到,我们在单个语句中使用LINQ和Lambda表达式指定不同的查询条件,因此,LINQ使代码更加紧凑和可读,并且它也可以用于查询不同的数据源。

三.LINQ的优点

  • 1.linq可以用最少的代码对集合执行查询,筛选、排序和分组操作。

  • 2.统一查询语句

长期以来,开发社区形成以下的格局:

1、面向对象与数据访问两个领域长期分裂,各自为政。

2、编程语言中的数据类型与数据库中的数据类型形成两套不同的体系,例如:C#中字符串用string数据类型表示。SQL中字符串用NVarchar/Varchar/Char数据类型表示。

3、SQL编码体验落后,没有智能感知效果,没有严格意义上的强类型和类型检查。

扫描二维码关注公众号,回复: 13721492 查看本文章

4、SQL和XML都有各自的查询语言,而对象没有自己的查询语言。

上面描述的问题,都可以使用LINQ解决。LINQ使你可以使用统一的方式编写各种查询。用于保存和检索来自不同数据源的数据,从而消除了编程语言和数据库之间的不匹配,以及为不同类型的数据源提供单个查询接口。

四.LINQ的功能

LINQ 系列技术提供了针对对象 (LINQ to Objects)、关系数据库 (LINQ to SQL) 和 XML (LINQ to XML) 的一致查询体验。

但是**语言集成查询 (LINQ) **不只是查询数据。 它也是用于转换数据的强大工具。 通过使用 LINQ 查询,可以使用源序列作为输入,并通过多种方式对其进行修改,以创建新的输出序列。 通过排序和分组,你可以修改序列本身,而无需修改这些元素本身。 但也许 LINQ 查询最强大的功能是创建新类型。 这可以在 select 子句中完成。 例如,可以执行下列任务:

  • 将多个输入序列合并为具有新类型的单个输出序列。
  • 创建其元素由源序列中每个元素的一个或多个属性组成的输出序列。
  • 创建其元素由对源数据执行的操作结果组成的输出序列。
  • 创建其他格式的输出序列。 例如,可以将数据从 SQL 行或文本文件转换为 XML。

这只是几个例子。 当然,可以以各种方式在同一查询中组合这些转换。 此外,一个查询的输出序列可以用作新查询的输入序列。

五.LINQ查询操作

有 LINQ 查询操作都由以下三个不同的操作组成:

  1. 获取数据源。
  2. 创建查询。
  3. 执行查询。
class IntroToLINQ
{
    
    
    static void Main()
    {
    
    
        // The Three Parts of a LINQ Query:
        // 1. 获取数据源.
        int[] numbers = new int[7] {
    
     0, 1, 2, 3, 4, 5, 6 };

        // 2. 创建查询.
        // numQuery is an IEnumerable<int>
        var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;

        // 3. 执行查询.
        foreach (int num in numQuery)
        {
    
    
            Console.Write("{0,1} ", num);
        }
    }
}

下图演示完整的查询操作。 在 LINQ 中,查询的执行不同于查询本身。 换句话说,仅通过创建查询变量不会检索到任何数据。
在这里插入图片描述

1.数据源

上例中,数据源是一个数组,因此它隐式支持泛型 IEnumerable 接口。 我们称 支持 IEnumerable 或派生接口(如泛型 IQueryable)的类型称为可查询类型 。

2.创建查询语句

查询指定要从数据源中检索的信息。 查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始化。 为使编写查询的工作变得更加容易,C# 引入了新的查询语法。

上一个示例中的查询从整数数组中返回所有偶数。 该查询表达式包含三个子句:fromwhereselect。 (如果熟悉 SQL,会注意到这些子句的顺序与 SQL 中的顺序相反。)from 子句指定数据源,where 子句应用筛选器,select 子句指定返回的元素的类型。 语言集成查询 (LINQ) 一节中详细讨论了这些子句和其他查询子句。 目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。 它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。 有关在后台如何构造查询的详细信息,请参阅标准查询运算符概述 (C#)

4.查询执行

a.延迟执行

如前所述,查询变量本身只存储查询命令。 查询的实际执行将推迟到在 foreach 语句中循环访问查询变量之后进行。 此概念称为 延迟执行,下面示例:

//  Query execution.
foreach (int num in numQuery)
{
    
    
    Console.Write("{0,1} ", num);
}

foreach 语句也是检索查询结果的地方。 例如,在上一个查询中,迭代变量 num 保存了返回的序列中的每个值(一次保存一个值)。

由于查询变量本身从不保存查询结果,因此可以根据需要随意执行查询。 例如,可以通过一个单独的应用程序持续更新数据库。 在应用程序中,可以创建一个检索最新数据的查询,并可以按某一时间间隔反复执行该查询以便每次检索不同的结果。

b.强制立即执行

对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。 CountMaxAverageFirst 就属于此类查询。 由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。 另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。 下面的查询返回源数组中偶数的计数:

var evenNumQuery =
    from num in numbers
    where (num % 2) == 0
    select num;

int evenNumCount = evenNumQuery.Count();

要强制立即执行任何查询并缓存其结果,可调用 ToListToArray 方法。

List<int> numQuery2 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToList();

// or like this:
// numQuery3 is still an int[]
var numQuery3 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToArray();

此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。 但是,通过调用 ToListToArray,也可以将所有数据缓存在单个集合对象中。

六.LINQ 中的查询语法和方法语法

一般介绍LINQ的文档中的大多数查询是使用 LINQ 声明性查询语法编写的。 但是在编译代码时,查询语法必须转换为针对 CLR 的方法调用。 这些方法调用会调用标准查询运算符(名称为 WhereSelectGroupByJoinMaxAverage 等)。 可以使用方法语法(而不是查询语法)来直接调用它们。查询语法方法语法在语义上是相同的。

下面的示例演示一个简单的查询语法方法语法等效的查询:

class QueryVMethodSyntax
{
    
    
    static void Main()
    {
    
    
        int[] numbers = {
    
     5, 10, 8, 3, 6, 12};

        //查询语法:
        IEnumerable<int> numQuery1 =
            from num in numbers
            where num % 2 == 0
            orderby num
            select num;

        //方法语法:
        IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);

        foreach (int i in numQuery1)
        {
    
    
            Console.Write(i + " ");
        }
        Console.WriteLine(System.Environment.NewLine);
        foreach (int i in numQuery2)
        {
    
    
            Console.Write(i + " ");
        }
    }
}
/*
    Output:
    6 8 10 12
    6 8 10 12
 */

七.查询语法关键字

查询表达式中使用的上下文关键字。
示例代码:

// 查询表达式语法.  
var query = from word in words  
            group word.ToUpper() by word.Length into gr  
            orderby gr.Key  
            select new {
    
     Length = gr.Key, Words = gr };  
子句 说明
from 指定数据源和范围变量(类似于迭代变量)。
where 基于由逻辑 AND 和 OR 运算符(&&||)分隔的一个或多个布尔表达式筛选源元素。
select 指定执行查询时,所返回序列中元素的类型和形状。
group 根据指定的密钥值对查询结果分组。
into 提供可作为对 join、group 或 select 子句结果引用的标识符。
orderby 根据元素类型的默认比较器对查询结果进行升序或降序排序。
join 基于两个指定匹配条件间的相等比较而联接两个数据源。
let 引入范围变量,在查询表达式中存储子表达式结果。
in join 子句中的上下文关键字。
on join 子句中的上下文关键字。
equals join 子句中的上下文关键字。
by group 子句中的上下文关键字。
ascending orderby 子句中的上下文关键字。
descending orderby 子句中的上下文关键字。

八.方法语法运算符

标准查询运算符 是组成 LINQ 模式的方法。 这些方法中的大多数都作用于序列;其中序列指其类型实现 IEnumerable 接口或 IQueryable 接口的对象。 标准查询运算符提供包括筛选、投影、聚合、排序等在内的查询功能。
在这里插入图片描述

示例代码:

// 使用标准方法查询语法 
var query = words.  
    GroupBy(w => w.Length, w => w.ToUpper()).  
    Select(g => new {
    
     Length = g.Key, Words = g }).  
    OrderBy(o => o.Length);  

查询表达式语法表

下表列出包含等效查询表达式子句的标准查询运算符。

方法 C# 查询表达式语法
Cast 使用显式类型化范围变量,例如: from int i in numbers (有关详细信息,请参阅 from 子句。)
GroupBy group … by - 或 - group … by … into … (有关详细信息,请参阅 group 子句。)
GroupJoin(IEnumerable, IEnumerable, Func, Func, Func,TResult>) join … in … on … equals … into … (有关详细信息,请参阅 join 子句。)
Join(IEnumerable, IEnumerable, Func, Func, Func) join … in … on … equals … (有关详细信息,请参阅 join 子句。)
OrderByDescending(IEnumerable, Func) orderby … descending (有关详细信息,请参阅 orderby 子句。)
Select select (有关详细信息,请参阅 let 子句。)
SelectMany 多个 from 子句。 (有关详细信息,请参阅 from 子句。)
ThenBy(IOrderedEnumerable, Func) orderby …, … (有关详细信息,请参阅 orderby 子句。)
ThenByDescending(IOrderedEnumerable, Func) orderby …, … descending (有关详细信息,请参阅 orderby 子句。)
Where where (有关详细信息,请参阅 where 子句。)
OrderBy(IEnumerable, Func) orderby (有关详细信息,请参阅 orderby 子句。)

扩展标准查询运算符

通过扩展标准查询的方法,可以增大标准查询运算符的集合。 也可以用自己的实现来替换标准查询运算符,请参考:

其他标准查询运算

通过以下链接可转到一些文章,这些文章基于功能提供有关各种标准查询运算符的附加信息。

对数据进行排序 (C#)

集运算 (C#)

筛选数据 (C#)

限定符运算 (C#)

投影运算 (C#)

数据分区 (C#)

联接运算 (C#)

数据分组 (C#)

生成运算 (C#)

相等运算 (C#)

元素运算 (C#)

转换数据类型 (C#)

串联运算 (C#)

聚合运算 (C#)

猜你喜欢

转载自blog.csdn.net/qq563129582/article/details/120896197