语言集成查询LINQ

news/2025/1/22 9:29:33/

定义:语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称(用C#语言就能查询(数据库)等数据源的查询)

IEnumerable和List的区别:IEnumerable是一个接口,只能用来遍历里面的数据
ListList是一个类,它实现了IEnumerable接口,提供了丰富的成员方法,如Add、Remove、Clear、Sort等

LINQ表达式查询语法:以 from 子句开头,且必须以 select 或 group 子句结尾

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//查询变量
var evenNumbersSorted = from number in numberswhere number % 2 == 0orderby numberselect number;//select选择要返回的结果

方法语法:一般联合lamdba表达式一起使用:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };var evenNumbersSorted = numbers.Where(number => number % 2 == 0).OrderBy(number => number).ToList();

查询语法和方法语法可以联合使用
.Max()、Count()为方法语法

//不是查询变量的变量(因为储存了值)
int maxValue = (from number in numbersselect number).Max();
int countAboveHalfMax = (from number in numberswhere number > maxValue / 2select number).Count();

查询时不会立即执行,必须使用 foreach 来返回结果,但是也可以通过方法,强制执行

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

查询结束语句:group/select

group 子句

group 子句返回一个 IGrouping<TKey,TElement> 对象序列,,可以按照每个字符串中的第一个字母对字符串序列进行分组。 在这种情况下,第一个字母就是键,类型为 char,要对每个组执行附加查询操作,可使用上下文关键字 into 指定一个临时标识符。并最终使用一个select 语句或另一个 group 子句结束该查询

var studentQuery2 =from student in studentsgroup student by student.Last[0] into gorderby g.Key//对分组进行排序select g;

对分组后的结果查询:嵌套循环遍历:第一层遍历出每个键值的组,第二层遍历每个组中的元素

foreach (IGrouping<char, Student> studentGroup in studentQuery2)
{Console.WriteLine(studentGroup.Key);foreach (var student in studentGroup){Console.WriteLine("   {0}, {1}", student.Last, student.First);}}

分组键可以是任意类型:
比如按照数值范围分组:

var studentQuery =from student in studentslet avg = (int)student.Scores.Average()group student by (avg / 10) into g  //按照每个学生的分/10取整分组,这样在0-9,10-19....按照每十个区间的方式分组orderby g.Keyselect g;// Execute the query.foreach (var studentGroup in studentQuery){int temp = studentGroup.Key * 10;Console.WriteLine("Students with an average between {0} and {1}", temp, temp + 10);foreach (var student in studentGroup){Console.WriteLine("   {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());}}

复合建分组:

group person by new {name = person.surname, city = person.city};

直接返回分组后的结果

List<int> numbers = [35, 44, 200, 84, 3987, 4, 199, 329, 446, 208];IEnumerable<IGrouping<int, int>> query = from number in numbersgroup number by number % 2;
//方法语法
IEnumerable<IGrouping<int, int>> query = numbers.GroupBy(number => number % 2);

select 子句

可以选择返回查询出序列中的元素类型,
默认和数据源序列中元素类型一样,也可显示转换

//默认
IEnumerable<Country> sortedQuery =from country in countriesorderby country.Areaselect country;
//转换(映射)
var queryNameAndPop =from country in countriesselect new{Name = country.Name,Pop = country.Population};

使用“into”延续

如果select或group后还要继续进行查询,那么就可以通过into重命名查询结果,然后继续筛选查询

var percentileQuery =from country in countrieslet percentile = (int)country.Population / 10_000_000group country by percentile into countryGroupwhere countryGroup.Key >= 20//筛选出键值>=20的组orderby countryGroup.Key select countryGroup;

联表查询join

join 子句可用于将来自不同源序列并且在对象模型中没有直接关系的元素相关联。 唯一的要求是每个源中的元素需要共享某个(主键、外键)可以进行比较以判断是否相等的值。join 子句的输出形式取决于执行的联接的具体类型

内部链接
//查询语句
var innerJoinQuery =from category in categoriesjoin prod in products on category.ID equals prod.CategoryID //两表中只有相等的才会连接上select new { ProductName = prod.Name, Category = category.Name }; 
//方法语句
var innerJoinQuery=category.join(products,category=>category.ID,prod=>prod.CategoryID, (category,prod)=>new{ProductName=prod.name,Category = category.Name });

分组联接

含有 into 表达式的 join 子句
将每组链接的结果,单独作为一个对象,继续之后的操作

var innerGroupJoinQuery2 =from category in categoriesjoin prod in products on category.ID equals prod.CategoryID into prodGroupfrom prod2 in prodGroupwhere prod2.UnitPrice > 2.50Mselect prod2;//方法语句
var innerGroupJoinQuery2=categories.groupJoin(products,
category=>category.ID,
prod=>prod.CategoryID, 
(category,prod)=>prodGroup,
where(prod2=>prod2.UnitPrice > 2.50M),
select(prod2=>prod2)
).SelectMany(group => group);//展开分组

复合键

IEnumerable<string> query =from teacher in teachersjoin student in students on new{FirstName = teacher.First,LastName = teacher.Last} equals new{student.FirstName,student.LastName}select teacher.First + " " + teacher.Last;
//方法语法
IEnumerable<string> query =teachers.join(students,teacher=>new{FirstName = teacher.First,LastName = teacher.Last},student=>new{student.FirstName,student.LastName},(teacher,student)=> $"{teacher.First} {teacher.Last}");

多个join

var query = from student in studentsjoin department in departments on student.DepartmentID equals department.IDjoin teacher in teachers on department.TeacherID equals teacher.IDselect new {StudentName = $"{student.FirstName} {student.LastName}",DepartmentName = department.Name,TeacherName = $"{teacher.First} {teacher.Last}"};
//方法语句
var query = students.Join(departments, student => student.DepartmentID, department => department.ID,(student, department) => new { student, department }).Join(teachers, commonDepartment => commonDepartment.department.TeacherID, teacher => teacher.ID,(commonDepartment, teacher) => new{StudentName = $"{commonDepartment.student.FirstName} {commonDepartment.student.LastName}",DepartmentName = commonDepartment.department.Name,TeacherName = $"{teacher.First} {teacher.Last}"});

执行左外部联接

使用 LINQ 通过对分组 join 的结果调用 DefaultIfEmpty 方法来执行左外部 join。
第一步内联:
Department 对象列表基于与学生的 DepartmentID 匹配的 Department 对象的 ID,内部联接到 Student 对象列表。
第二部:
然后,您使用另一个from子句来展开这个中间序列,同时利用DefaultIfEmpty()方法来确保即使没有找到匹配的部门,学生记录仍然会被包含在结果中。

var query =from student in studentsjoin department in departments on student.DepartmentID equals department.ID into gjfrom subgroup in gj.DefaultIfEmpty()select new{student.FirstName,student.LastName,Department = subgroup?.Name ?? string.Empty};
//方法语句
var query = students.GroupJoin(departments,student => student.DepartmentID,department => department.ID,(student, departmentList) => new { student, subgroup = departmentList })//subgroup包含了每次匹配成功后的右表记录.SelectMany(joinedSet => joinedSet.subgroup.DefaultIfEmpty(),//即使匹配到的右表是null,任然保存左表的那行记录(student, department) => new{student.student.FirstName,student.student.LastName,Department = department.Name});

let 子句

将表达式的结果保存到新的范围变量中

string[] names = ["Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia"];
IEnumerable<string> queryFirstNames =from name in nameslet firstName = name.Split(' ')[0]select firstName;foreach (var s in queryFirstNames)
{Console.Write(s + " ");
}

对分组操作执行子查询

ar queryGroupMax =from student in studentsgroup student by student.Year into studentGroupselect new{Level = studentGroup.Key,HighestScore = (//找出力每个组中,每个学生的平均成绩的最高分from student2 in studentGroup  select student2.Scores.Average()).Max()};
//方法语句```csharp
var queryGroupMax =students.GroupBy(student => student.Year).Select(studentGroup => new{Level = studentGroup.Key,HighestScore = studentGroup.Max(student2 => student2.Scores.Average())});

``

在运行时动态指定谓词筛选器Contains方法

当筛选条件不单一,则使用Contains方法

int[] ids = [111, 114, 112];var queryNames =from student in studentswhere ids.Contains(student.ID)//筛选出student.ID在ids集合中的学生select new{student.LastName,student.ID};

在查询表达式中处理 null 值

编码防御型:

var query1 =from c in categorieswhere c != nulljoin p in products on c.ID equals p?.CategoryIDselect new{Category = c.Name,Name = p.Name};

http://www.ppmy.cn/news/1565186.html

相关文章

.NET Core 中如何构建一个弹性HTTP 请求机制

1. 理解弹性 HTTP 请求机制 什么是弹性? 弹性是指系统在面对故障或异常情况时,能够保持或快速恢复到正常状态的能力。在 HTTP 请求的上下文中,弹性意味着当请求失败时,系统能够自动采取一系列措施(如重试、降级、断路等)来确保请求最终成功或优雅地处理失败。 为什么需…

2.C++的变量,输入,输出

C的变量&#xff0c;输入&#xff0c;输出 同其它编程语言一样&#xff0c;C程序要想与用户进行交互&#xff0c;必须有输出&#xff0c;输入&#xff0c;还有存储数据的变量。接下来我们一起来看看在C中如何进行输入输出&#xff0c;以及变量的存储吧。 输出 在编程业界有个…

HotSpot JVM中的两种模式

这里写自定义目录标题 **1. Client 模式****特点**&#xff1a;**优化目标**&#xff1a;**启动参数**&#xff1a; **2. Server 模式****特点**&#xff1a;**优化目标**&#xff1a;**启动参数**&#xff1a; **Client 模式 vs Server 模式&#xff1a;比较****3. 自动选择模…

基于Python django的音乐用户偏好分析及可视化系统设计与实现

1.1 论文背景 随着信息技术的快速发展&#xff0c;在线音乐服务已成为日常生活的重要组成部分。QQ音乐&#xff0c;凭借其创新的音乐推荐算法和独特的社交特性&#xff0c;成功在竞争激烈的市场中获得一席之地。该平台的歌单文化和评论文化不仅满足了用户自尊和自我实现的需求…

区块链 智能合约安全 | 回滚攻击

视频教程在我主页简介和专栏里 目录&#xff1a; 智能合约安全 回滚攻击 总结 智能合约安全 回滚攻击 回滚攻击的本质是”耍赖” 举一个简单的例子,两个人玩石头剪刀布,输了的给对方10块钱,现在A输了,A说这把不算,重来 放在Solidity中,require()函数会检测其中的条件是否满…

为什么数据库不应该使用外键

一、引言 当我们需要持久化地存储数据时&#xff0c;关系型数据库通常是首选。它不仅种类丰富、稳定&#xff0c;而且得到了广泛社区的支持。本文将探讨关系型数据库中的一个重要概念——外键&#xff08;Foreign Key&#xff09;。 二、外键的作用 在关系型数据库中&#xf…

02内存结构篇(D4_JVM内存分配机制)

目录 一、对象的创建 1. 类加载检查 2. 分配内存 3. 初始化零值 4. 设置对象头 32位对象头 64位对象头 5. 执行方法 二、对象大小与指针压缩 三、对象内存分配 1. 对象内存分配流程图 2. 对象栈上分配 3.3 对象在Eden区分配 3.4 大对象直接进入老年代 3.5 长期存…

md中的特殊占位文件路径的替换

结构 :::readFile /xx/xx.vue :::将/xx/xx.vue进行替换出来 const extractContentAll (str, prefix, suffix) > {const pattern new RegExp(${prefix}(.*?)${suffix}, "sg");const match str.match(pattern);return match ? match : null;};const extractC…