LINQ详解(查询表达式)
什么是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 Numswhere num > 80select num;
//执行查询
foreach(int num in numQuery)
{Console.WriteLine("num={0}", num);
}
查询表达式概述
查询表达式可用于查询并转换所有启用了LINQ
的数据源中的数据。如,通过一个查询可以检索数据库中的数据,并生成指定的格式(如XML
流)作为输出。
查询表达式容易掌握,因为大部分是熟悉的C#语法。
查询表达式中的变量都是强类型,在大部分情况下,不需要显示提供类型,因为编译器可以进行自行推断出。
只有在循环访问查询变量后,才会执行查询(如foreach
语句)。
在编译时,查询表达式根据C#
语法规范转换成标准查询运算符方法调用。在查询中,使用的查询语法都可以使用方法语法进行表示。但是,查询语法的可读性更好,更简洁。
在编写LINQ
查询时尽量使用查询语法,在必要时使用方法语法。这两种形式在语义或性能上毫无差异,使用查询语法比使用方法语法编写的等同表达式具有更好的可读性。
一次查询操作(如Count
或Max
)没有等效的查询表达式字句,因此必须表示为方法调用,可以通过各种方式结合使用方法语法和查询语法。
查询表达式可被编译成表达式树或委托,具体应根据查询类型而定。
IEnumerable<T>
查询编译为委托。IQueryable
和IQueryable<T>
查询编译为表达式树。
查询表达式
在进行了解之前,我们首先要思考的是:查询是什么?及其作用是什么?
查询是一组指令,描述要从给定的数据源中检索数据以及返回的数据应具有的形状和组织。查询与它生成的结果不同。
通常情况下,源数据按逻辑方式组织为相同类型的元素序列。如,SQL
数据库表包含行的序列。在XML
文件中,存在XML
元素的序列(这些元素在树结构按层次结构进行组织)。内存中集合包含的对象序列。
从应用程序的角度来讲,原始源数据的特定类型和结构并不重要。应用程序始终将原始数据视为IEnumerable<T>
或IQueryable<T>
集合。如,在XML
中,源数据显示为IEnumerable<XElement>
。
查询表达式必须以from
子句开头,它指定数据源和范围变量,范围变量表示遍历源序列时,源序列中的每个连续元素,范围变量基于数据源中元素的类型进行强类型化。如下示例所示,countries
是Country
对象的数组,所以范围变量的类型为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 Numswhere num > 80orderby num descendingselect num;
2、如前面的示例所示检索元素的序列,但是将它们转换为新类型的对象。如,查询可以只从数据源中的某些客户记录检索姓氏,或者可以检索完整记录,
IEnumerable<string> queryStr = from num in querywhere num > 80orderby num descendingselect string.Format("The number id {0}", num);
3、检索有关源数据的单独值,如:与特定条件匹配的元素数;具有最大或最小值的元素;与某个条件匹配的第一个元素。如下例子所示:
int hightCount = (from num in Numswhere num > 85select num).Count();
在上面的示例中,在调用Count
方法之前,在查询表达式两边使用了括号,也可以通过使用新变量存储结果,这种写法更具有可读性,因为它使存储查询的变量与存储结果的查询分开,如下例子所示:
IEnumerable<int> hightQuery = from num in Numswhere num > 90select num;int hightCounts = hightQuery.Count();
查询表达式是什么?
查询表达式是以查询语法表示的查询。查询表达式由一组类似于SQL
或XQuery
的声明性语法所编写的字句组成,每个字句包含一个或多个C#
表达式,而这些表达式本身可能是查询表达式或包含查询表达式。
查询表达式必须以from
字句开头,且必须以select
或group
字句结尾。在from
和select
或group
之间,可以包含以下这些可选子句中的一个或多个:where
、orderby
、join
、let
,甚至是其它from
子句。还可以使用into
关键字,使join
或group
子句的结果可以充当相同查询表达式中的其它查询表达式的源。
查询变量
在LINQ
中,查询变量存储查询而不是查询结果的任何变量。查询变量始终是可枚举类型,在foreach
语句或对其IEnumerator.MoveNext
方法的直接调用中循环访问时会生成元素序列。
查询变量可以存储采用查询语法、方法语法或两者的组合进行表示的查询,如以下示例中,majorCity
和majorCity2
都是查询变量。
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 cityListwhere city.Population > 120000select 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
对象的集合,每个对象都包含名为Cities
的City
对象集合,若要查询每个County
中的City
对象,请使用两个from
子句。
IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
使用into
进行延续
可以在select
或group
子句中使用into
关键字创建存储查询的临时标识符。如果在group
或select
操作之后必须对查询执行其它查询操作,可以使用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
子句与结尾select
或group
子句之间,所有其它子句(where
、join
、orderby
、from
、let
)都是可选的,任何可选子句在查询中可以使用零次或多次。
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
中,联接操作是对不同类型的对象序列执行,联接两个序列之后,必须使用select
或group
语句指定要存储在输出序列中的元素,还可以使用匿名类型将每组关联元素中的属性合并到输出序列中的新类型。如下示例所示,关联其Category
属性与categories
字符串数组中一个类别匹配的prod
对象,筛选出Category
与categories
数组中任何匹配的字符串,select
语句投影其属性取自cat
和prod
的新类型。
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 strlet 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 cityListgroup city by city.Population into newCityselect new{Level = newCity.Key,maxKey = (from cityMax in newCityselect cityMax.Population).Max()};
这次就先讲到这里啦,下次在讲解LINQ
的方法语法,热烈欢迎各位广大网友进行批评指正。
相关文章:

LINQ详解(查询表达式)
什么是LINQ? LINQ(语言集成查询)是将查询功能直接集成到C#中。数据查询表示简单的字符串,在编译时不会进行类型检查和IntelliSense(代码补全辅助工具)支持。 在开发中,通常需要对不同类型的数据源了解不同的查询语句,如SQL数据库…...
【DEVOPS】现状篇
0. 目录 1. 前言2. 现状2.1 需求管理2.2 开发流程2.3 测试流程2.4 部署流程2.5 维护阶段 3. 后记4. 相关 1. 前言 一直以来,深感内部工程化能力欠缺,急于将事情向前推进,总是希望能够向前走几步,再走几步。 可惜的是,…...

Linux文件管理知识:查找文件(第二篇)
Linux文件管理知识:查找文件(第二篇) 上篇文章详细介绍了linux系统中查找文件的工具或者命令程序locate和find命令的基本操作。那么,今天这篇文章紧接着查找文件相关操作内容介绍。 Find命令所属操作列表中的条目,有助于我们想要…...

医疗小程序:让服务更高效,用户体验更优化
随着移动互联网的快速发展,小程序已经成为了一个热门的开发方向。医疗健康类小程序也不例外,拥有广泛的市场需求和前景。本文将为你提供一份完整的医疗健康类小程序开发攻略,帮助你快速开发上线一个专业成熟的小程序商城。 一、选择合适的小程…...
C++11 std::transform函数使用说明
std::transform是C标准库中的一个算法,它用于对输入范围内的元素进行操作,并将结果存储在输出范围内。这个算法特别适合于将一种数据类型转换为另一种数据类型。 函数定义在头文件algorithm中 std::transform的基本语法如下: std::transfor…...
JavaScript-DOM查询
获取元素节点 获取元素节点的子节点 元素节点的属性 节点的修改 JavaScript中的DOM(文档对象模型)是一种编程接口,它允许JavaScript与HTML文档交互。创建DOM查询,可以使用多种方法. 获取元素节点 1. getElementById() – 通…...

大数据-玩转数据-Flink 水印
一、Flink 中的水印 在Flink的流式操作中, 会涉及不同的时间概念: 1.1 处理时间 是指的执行操作的各个设备的时间,对于运行在处理时间上的流程序, 所有的基于时间的操作(比如时间窗口)都是使用的设备时钟。比如, 一个长度为1个小时的窗口将会包含设备…...

【Apollo】阿波罗自动驾驶系统:驶向未来的智能出行(含源码安装)
前言 Apollo (阿波罗)是一个开放的、完整的、安全的平台,将帮助汽车行业及自动驾驶领域的合作伙伴结合车辆和硬件系统,快速搭建一套属于自己的自动驾驶系统。 开放能力、共享资源、加速创新、持续共赢是 Apollo 开放平台的口号。百度把自己所拥有的强大、…...
网络-Netty
how pipeline.addLast(ChannelHandler)...
如何使用vue-smooth-dnd
Vue Smooth DnD是一个基于Vue的平滑易用的拖放库。它提供了简单易用的API和可自定义的样式。 要使用Vue Smooth DnD,可以按照以下步骤进行操作: 安装Vue Smooth DnD npm install vue-smooth-dnd --save 在组件中引入Vue Smooth DnD import VueSmoot…...
为AWS认证做好准备:一份全面的备考指南
随着云计算的快速发展,越来越多的专业人士选择获取AWS(亚马逊网络服务)认证。这个认证不仅可以证明你对AWS的理解和专业技能,还有助于你在云计算领域获得更好的工作机会。 以下是一份全面的备考指南,帮助你为AWS认证做…...
尚硅谷SpringMVC
九、HttpMessageConverter...

django的简易的图书管理系统jsp书店进销存源代码MySQL
本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 django的简易的图书管理系统 系统有1权限:…...
力扣125. 验证回文串
125. 验证回文串 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s,如果它是 回文串 ,返回 true &…...
用WebStorm创建Mock数据
WebStorm是一款强大的集成式开发环境,它集成了许多实用的功能,包括Mock数据的创建。 下面是用WebStorm创建Mock数据的步骤: 打开WebStorm,选择一个项目或新建一个项目;在项目中创建一个名为“mock”的文件夹…...

Python钢筋混凝土结构计算.pdf-已知弯矩确定混凝土梁截面尺寸
计算原理 确定混凝土梁截面的合理尺寸通常需要考虑弯矩、受力要求和约束条件等多个因素。以下是一种常见的计算公式,用于基于已知弯矩确定混凝土梁截面的合理尺寸: 请注意,以上公式仅提供了一种常见的计算方法,并且具体的规范和设…...
【正点原子STM32连载】第二十四章 高级定时器PWM输入模式实验 摘自【正点原子】APM32F407最小系统板使用指南
1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html# 第二…...

Adapter Tuning Overview:在CV,NLP,多模态领域的代表性工作
文章目录 Delta TuningAdapter Tuning in CVAdapter Tuning in NLP Delta Tuning Adapter Tuning in CV 题目: Learning multiple visual domains with residual adapters 机构:牛津VGG组 论文: https://arxiv.org/pdf/1705.08045.pdf Adapter Tuning in NLP …...
velocity一个基于Java的模板引擎
参考:https://blog.csdn.net/m0_51517236/article/details/126175283 http://www.51gjie.com/javaweb/896.html...
异步servlet
我们日常使用的 SpringMVC,基本上都不是异步 Servlet,而学习 WebFlux,异步 Servlet 是基础,WebFlux。 1.什么是异步 Servlet 先来说说什么是非异步 Servlet。 在 Servlet3.0 之前,Servlet 采用 Thread-Per-Request 的方…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...