LINQ详解(查询表达式)

news2024/11/21 2:29:01

什么是LINQ?

LINQ(语言集成查询)是将查询功能直接集成到C#中。数据查询表示简单的字符串,在编译时不会进行类型检查和IntelliSense(代码补全辅助工具)支持。

在开发中,通常需要对不同类型的数据源了解不同的查询语句,如SQL数据库、XML文档、各种Web服务等。为了使每种类型的查询语句统一,通过借助LINQ,查询成了最高级的语言构造,就像类、方法、事件一样,可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。LINQ提供了针对对象、关系数据库、XML的查询技术。

LINQ最明显的语言集成部分是查询表达式,查询表达式采用声明性语法编写,可以通过最少的代码对数据源进行筛选、排序和分组等操作,也可以使用相同的基本查询表达模式来查询和转换SQL数据库、ADO.NET数据集、XML文档和流、.NET集合中的数据。

SQL Server数据库、XML文档和流、ADO.NET数据集、支持IEnumerable或泛型IEnumerable<T>接口的任何对象集合都可以使用LINQ查询。
例如:

 //创建数据源
int[] Nums = { 86, 89, 95, 93, 79, 86, 99 };

//定义查询表达式
IEnumerable<int> numQuery = from num in Nums
                            where num > 80
                            select num;
//执行查询
foreach(int num in numQuery)
{
    Console.WriteLine("num={0}", num);
}

在这里插入图片描述

查询表达式概述

查询表达式可用于查询并转换所有启用了LINQ的数据源中的数据。如,通过一个查询可以检索数据库中的数据,并生成指定的格式(如XML流)作为输出。

查询表达式容易掌握,因为大部分是熟悉的C#语法。

查询表达式中的变量都是强类型,在大部分情况下,不需要显示提供类型,因为编译器可以进行自行推断出。

只有在循环访问查询变量后,才会执行查询(如foreach语句)。

在编译时,查询表达式根据C#语法规范转换成标准查询运算符方法调用。在查询中,使用的查询语法都可以使用方法语法进行表示。但是,查询语法的可读性更好,更简洁。

在编写LINQ查询时尽量使用查询语法,在必要时使用方法语法。这两种形式在语义或性能上毫无差异,使用查询语法比使用方法语法编写的等同表达式具有更好的可读性。

一次查询操作(如CountMax)没有等效的查询表达式字句,因此必须表示为方法调用,可以通过各种方式结合使用方法语法和查询语法。

查询表达式可被编译成表达式树或委托,具体应根据查询类型而定。

IEnumerable<T>查询编译为委托。IQueryableIQueryable<T>查询编译为表达式树。

查询表达式

在进行了解之前,我们首先要思考的是:查询是什么?及其作用是什么?

查询是一组指令,描述要从给定的数据源中检索数据以及返回的数据应具有的形状和组织。查询与它生成的结果不同。

通常情况下,源数据按逻辑方式组织为相同类型的元素序列。如,SQL数据库表包含行的序列。在XML文件中,存在XML元素的序列(这些元素在树结构按层次结构进行组织)。内存中集合包含的对象序列。

从应用程序的角度来讲,原始源数据的特定类型和结构并不重要。应用程序始终将原始数据视为IEnumerable<T>IQueryable<T>集合。如,在XML中,源数据显示为IEnumerable<XElement>

查询表达式必须以from子句开头,它指定数据源和范围变量,范围变量表示遍历源序列时,源序列中的每个连续元素,范围变量基于数据源中元素的类型进行强类型化。如下示例所示,countriesCountry对象的数组,所以范围变量的类型为Country,又范围变量为强类型,可以使用点运算符进行访问成员。

IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > 500000
select country;

查询表达式必须以select子句或group子句结尾。

使用select子句可生成所有其它类型的序列,简单的select子句只生成类型与数据源中包含的对象相同对象的类型。如下示例中,数据源中包含Country对象,orderby子句只按新顺序对元素进行排序,select子句生成重新排序的Country对象的序列。

IEnumerable<Country> sortedQuery =
from country in countries
orderby country.Area
select country;

select子句可以将源数据转换为新类型的序列,此转换称为投影。在如下示例中,select子句只包含原始元素中的字段子集的匿名类型序列进行投影。新对象使用对象初始值设定项进行初始化。

var queryNameAndPop =
from country in countries
select new { Name = country.Name, Pop = country.Population };

使用group子句可以生成按指定键组织的组的序列,键可以是任意类型的数据。如下示例所示,下面的查询会创建包含一个或多个country对象,并且其键是char值的组的序列。

var queryCountryGroups =
from country in countries
group country by country.Name[0];
foreach(IEnumerable<Country> country in queryCountryGroups )
{
   foreach(Country_country in country )
   {
       Console.WriteLine("City={0}", _country .Name);
   }
}

对于此源序列,查询可能会执行三种操作之一:

1、检索元素的子集以生成新序列,而不修改各个元素,然后可能以各种方式对返回的序列进行排序或分组。如下所示。

IEnumerable<int> query = from num in Nums
 where num > 80
 orderby num descending
 select num;

2、如前面的示例所示检索元素的序列,但是将它们转换为新类型的对象。如,查询可以只从数据源中的某些客户记录检索姓氏,或者可以检索完整记录,

IEnumerable<string> queryStr = from num in query
 where num > 80
 orderby num descending
 select string.Format("The number id {0}", num);

3、检索有关源数据的单独值,如:与特定条件匹配的元素数;具有最大或最小值的元素;与某个条件匹配的第一个元素。如下例子所示:

 int hightCount = (from num in Nums
 where num > 85
 select num)
 .Count();

在上面的示例中,在调用Count方法之前,在查询表达式两边使用了括号,也可以通过使用新变量存储结果,这种写法更具有可读性,因为它使存储查询的变量与存储结果的查询分开,如下例子所示:

IEnumerable<int> hightQuery = from num in Nums
 where num > 90
 select num;
 int hightCounts = hightQuery.Count();

查询表达式是什么?

查询表达式是以查询语法表示的查询。查询表达式由一组类似于SQLXQuery的声明性语法所编写的字句组成,每个字句包含一个或多个C#表达式,而这些表达式本身可能是查询表达式或包含查询表达式。

查询表达式必须以from字句开头,且必须以selectgroup字句结尾。在fromselectgroup之间,可以包含以下这些可选子句中的一个或多个:whereorderbyjoinlet,甚至是其它from子句。还可以使用into关键字,使joingroup子句的结果可以充当相同查询表达式中的其它查询表达式的源。

查询变量

LINQ中,查询变量存储查询而不是查询结果的任何变量。查询变量始终是可枚举类型,在foreach语句或对其IEnumerator.MoveNext方法的直接调用中循环访问时会生成元素序列。

查询变量可以存储采用查询语法、方法语法或两者的组合进行表示的查询,如以下示例中,majorCitymajorCity2都是查询变量。

List<City> cityList = new List<City>()
            {
 new City{ Population = 1000000},
 new City{Population = 100000},
 new City{Population = 10000},
 new City{Population = 540000}
            };
 //查询语法
 IEnumerable<City> majorCity = from city in cityList
 where city.Population > 120000
 select city;
 //方法语法
 IEnumerable<City> majorCity2 = cityList.Where(a => a.Population > 120000);

另一方面,以下示例演示不是查询变量的变量(即使各自使用查询进行初始化),它们不是查询变量,因为它们存储结果。

int highestScore =
(from score in scores
select score)
.Max();
// or split the expression
IEnumerable<int> scoreQuery =
from score in scores
select score;
int highScore = scoreQuery.Max();
// the following returns the same result
int highScore = scores.Max();
List<City> largeCitiesList =
(from country in countries
from city in country.Cities
where city.Population > 10000
select city)
.ToList();
// or split the expression
IEnumerable<City> largeCitiesQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
List<City> largeCitiesList2 = largeCitiesQuery.ToList();

查询表达式可能会包含多个from子句。在源序列中的每个元素本身就是集合或包含集合时,可以使用其它from子句。如下示例所示,假设具有County对象的集合,每个对象都包含名为CitiesCity对象集合,若要查询每个County中的City对象,请使用两个from子句。

IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;

使用into进行延续

可以在selectgroup子句中使用into关键字创建存储查询的临时标识符。如果在groupselect操作之后必须对查询执行其它查询操作,可以使用into关键字。在如下示例中,countries按1000万范围进行分组,创建这些分组之后,附加子句会筛选出一些组,然后按升序对组进行排序,若要执行这些附加操作,需要由countryGroup表示的延续。

var percentileQuery =
from country in countries
let percentile = (int) country.Population / 10000000
group country by percentile into countryGroup
where countryGroup.Key >= 20
orderby countryGroup.Key
select countryGroup;
// grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
Console.WriteLine(grouping.Key);
foreach (var country in grouping)
Console.WriteLine(country.Name + ":" + country.Population);
}

筛选、排序和联接

在开头from子句与结尾selectgroup子句之间,所有其它子句(wherejoinorderbyfromlet)都是可选的,任何可选子句在查询中可以使用零次或多次。

where子句

使用where子句可基于一个或多个表达式,从源数据中筛选出元素。如下示例所示。

IEnumerable<City> queryCityPop = 
from city in cities 
where city.Population < 200000 && city.Population > 100000 
select city; 

orderby子句

使用orderby子句可按升序或降序对结果进行排序,还可以指定次要排序顺序。如下示例所示,使用Area属性对country对象进行主要排序,Population属性进行次要排序。

IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;

ascending关键字是可选的,如果未指定任何顺序,则它是默认的排序顺序。

join子句

使用join子句基于每个元素中指定键之间的相等比较,将一个数据源中的元素与另一个数据源中的元素进行合并或关联。在LINQ中,联接操作是对不同类型的对象序列执行,联接两个序列之后,必须使用selectgroup语句指定要存储在输出序列中的元素,还可以使用匿名类型将每组关联元素中的属性合并到输出序列中的新类型。如下示例所示,关联其Category属性与categories字符串数组中一个类别匹配的prod对象,筛选出Categorycategories数组中任何匹配的字符串,select语句投影其属性取自catprod的新类型。

var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new { Category = cat, Name = prod.Name };

还可以使用into关键字,将join操作的结果存储到临时变量中来执行分组联接。
let子句
使用let子句可将表达式(如方法调用)的结果存储到新范围变量中。在如下示例中,范围变量f_name存储Split返回的字符串数组中的第一个元素。

            string[] str = { "kdh jsn", "lkhs nhdj", "sjjkd lsmkcj", "shdyfsh sjdnmds" };
            IEnumerable<string> queryName = from name in str
                                            let f_name = name.Split(' ')[0]
                                            select f_name;
            foreach(string name in queryName)
            {
                Console.WriteLine("name={0}", name);
            }

查询表达式中的子查询

查询子句本身可能包含查询表达式,也称为子查询。每个子查询都是以from子句开头,该子句不一定指向第一个from子句中相同的数据源。如下示例中,在select语句用于检索分组操作结果的查询表达式。

                           var groupMax = from city in cityList
                           group city by city.Population into newCity
                           select new
                           {
                               Level = newCity.Key,
                               maxKey = (
                                from cityMax in newCity
                                select cityMax.Population
                               ).Max()
                           };

这次就先讲到这里啦,下次在讲解LINQ的方法语法,热烈欢迎各位广大网友进行批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/955022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

⚠️ WinRAR 中的趋势漏洞 CVE-2023-38831

在漏洞区域 WinRAR 是一种流行的数据压缩程序。网络犯罪分子已经利用 CVE-2023-38831攻击交易者。 经纪账户面临风险 利用 CVE-2023-38831 漏洞&#xff0c;攻击者会创建 ZIP 压缩文件来传播各种恶意软件系列&#xff0c;如 DarkMe、GuLoader、Remcos RAT&#xff0c;并将其…

Zabbix --- Snmp Trap监控详细教程

一、zabbix服务器安装snmptrapd服务 1、安装服务 yum -y install net-snmp net-snmp-agent-libs net-snmp-devel net-snmp-libs net-snmp-perl net-snmp-utils 注&#xff1a;使用perl脚本解析trap信息并进行格式化&#xff0c;net-snmp-perl 2、zabbix启用snmptrap进程&…

react轮播图

这里 我用的是组件&#xff1a; 网址&#xff1a;Collapse 折叠面板 - Ant Design Mobile 1.首先 先声明一个变量 2、把需要的数据存存进去 3、组件内容复制过来&#xff08;这里用到的是map循环&#xff09; 然后图片就出来了 就是这个简单 哈哈哈哈&#xff01;&#xff01…

【Unity-Cinemachine相机】虚拟相机(Virtual Camera)的本质与基本属性

我们可以在游戏进行时修改各个属性&#xff0c;但在概念上&#xff0c;最好将Virtual Camera 当作一种相机行为的“配置文件”&#xff0c;而不是一个组件。 我们的相机有几种行为就为它准备几种虚拟相机&#xff0c;比如角色移动就为它第三人称相机&#xff0c;瞄准就准备一个…

Linux——守护进程

简述 不受用户登录、注销影响的进程称为守护进程 特点 后台运行&#xff1a;守护进程在后台默默地执行任务&#xff0c;不与用户交互。它不会向终端输出信息&#xff0c;也不会从终端接收输入。 无终端关联&#xff1a;守护进程通常与任何终端会话&#xff08;比如SSH会话&…

【c++5道练习题】①

目录 一、有限制的累加 二、计算日期到天数转换 三、仅仅反转字母 四、 字符串的第一个唯一字符 五、字符串最后一个单词的长度 一、有限制的累加 题述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句…

基于SpringBoot使用MyBatisPlus,MyBatisPlus标准数据层开发(CRUD)、MyBatisPlus分页功能的使用

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MyBatisPlus基础 一、入门案例1.1 创建新模块&…

深入理解Python中的多进程和多线程

前言 此篇文章将深入的讲解Python中的多进程和多线程 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 第一部分&#xff1a;多进程 多进程是指在操作系统中…

STL stack,queue,deque以及适配器

目录 stackstack的使用stack模拟实现 queuequeue的使用queue模拟实现 适配器deque stack stack的使用 下面是stack库中的接口函数&#xff0c;有了前面的基础&#xff0c;我们可以根据函数名得知函数的作用 函数说明stack()构造空栈empty()判断栈是否为空size()返回栈中元素…

keil5 快捷下载STM32系列芯片器件包的方法

以STM32H7系列的器件包为例,官网的下载网址为 https://sadevicepacksprodus.blob.core.windows.net/pack/Keil.STM32H7xx_DFP.3.1.1.pack 其中STM32H7xx为芯片系列编号,3.1.1为器件包的版本 如需下载其他系列和版本的器件包,只需把网址中的编号和版本换成对应的即可(前提是输入…

Websocket、SessionCookie、前端基础知识

目录 1.Websocket Websocket与HTTP的介绍 不同使用场景 Websocket链接过程 2.Session&Cookie Cookie的工作原理 Session的工作原理 区别 3.前端基础知识 1.Websocket Websocket与HTTP的介绍 HTTP&#xff1a; 1.HTTP是单向的&#xff0c;客户端发送请求&#xff0…

OWS.infg应用程序隐私政策

本软件尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务&#xff0c;本软件目前不会使用和披露您的个人信息。但本软件会不时更新本隐私权政策。您在同意本软件服务使用协议之时&#xff0c;即视为您已经同意本隐私权政策全部内容。本隐私权政策…

OJ练习第154题——到家的最少跳跃次数

到家的最少跳跃次数 力扣链接&#xff1a;1654. 到家的最少跳跃次数 题目描述 有一只跳蚤的家在数轴上的位置 x 处。请你帮助它从位置 0 出发&#xff0c;到达它的家。 跳蚤跳跃的规则如下&#xff1a; 它可以 往前 跳恰好 a 个位置&#xff08;即往右跳&#xff09;。 它…

【数据结构】——查找、散列表的相关习题

目录 一、选择填空判断题题型一&#xff08;顺序、二分查找的概念&#xff09;题型二&#xff08;分块查找的概念&#xff09;题型三&#xff08;关键字比较次数&#xff09; 二、应用题题型一&#xff08;二分查找判定树&#xff09; 一、选择填空判断题 题型一&#xff08;顺…

1、英飞凌-AURIX-TC297简介

目录 TC297简介TC297特点&#xff1a;系统优势最具创新性的安全应用场景 printf("欢迎关注公众号&#xff1a;Kevin的学习站/车载嵌入式探索者&#xff0c;博主建立了一个车规级开发交流群&#xff0c; 感兴趣的朋友可以关注公众号&#xff0c;加个人WX&#xff1a;_kevin…

医疗小程序:让服务更高效,用户体验更优化

随着移动互联网的快速发展&#xff0c;小程序已经成为了一个热门的开发方向。医疗健康类小程序也不例外&#xff0c;拥有广泛的市场需求和前景。本文将为你提供一份完整的医疗健康类小程序开发攻略&#xff0c;帮助你快速开发上线一个专业成熟的小程序商城。 一、选择合适的小程…

C++(17):异常处理

异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理。 异常使得能够将问题的检测与解决过程分离开来&#xff1a;程序的一部分负责检测问题的出现&#xff0c;然后解决该问题的任务传递给程序的另一部分。检测环节无须知道问题处理模块的…

Android 音频框架 基于android 12

文章目录 前言音频服务audioserver音频数据链路hal 提供什么样的作用 前言 Android 的音频是一个相当复杂的部分。从应用到框架、hal、kernel、最后到硬件&#xff0c;每个部分的知识点都相当的多。而android 这部分代码在版本之间改动很大、其中充斥着各种workaround的处理&a…

AI能完全取代PS吗?两者僵持背后的设计思路!

PS 是功能强大的位图图片处理软件。它的核心功能是图片处理&#xff0c;最大特点是放大图片时会出现马赛克模糊。PS 存在下载安装复杂&#xff0c;功能繁杂&#xff0c;新手不易上手等缺点。越来越多设计师更青睐轻量级的协作设计软件&#xff0c;例如新一代国产软件即时设计。…

openCV实战-系列教程11:文档扫描OCR识别上(轮廓检测/轮廓近似/透视变换/OCR识别)项目实战、源码解读

&#x1f9e1;&#x1f49b;&#x1f49a;&#x1f499;&#x1f49c;OpenCV实战系列总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 下篇内容&#xff1a; openCV实战-系列教程13&#xff1a;文档扫描OCR识别下&am…