当前位置: 首页 > article >正文

【EF Core】 EF Core 批量操作的进化之路——从传统变更跟踪到无跟踪更新

文章目录

  • 前言
  • 一、批量操作(Rang)
    • 1.1 AddRange()
    • 1.2 UpdateRange()
    • 1.3 AttachRange()
    • 1.4 RemoveRange()
  • 二、Range操作的底层优化
    • 2.1 EF Core 7 前举步维艰
    • 2.2 EF Core 7后焕然一新
  • 三、无跟踪的批量更新与删除
    • 3.1 ExecuteUpdate
    • 3.2 ExecuteDelete
    • 3.3 状态冲突
  • 总结


前言

众所周知,批量操作曾经一直是 EF Core被人广泛吐槽的一个点。当我们调用RemoveRangAsync()等批量操作方法时,想当然以为EF Core能将该代码翻译成一行删除语句。没想到底层实际执行的却是单独的一行一行删除语句。其实EF Core 实体跟踪的底层特性也注定了真正意义上的批量操作的实现难以实现,不过官方团队一直到EF Core 7 的版本终于开始实现了真正意义上的批量更新。

关于实体跟踪,大家可以去翻看我的这篇博客
链接: 《探秘EF Core 更改跟踪:实体状态、快照机制与调试优化技巧》


一、批量操作(Rang)

AddRange和RemoveRange的底层执行细节在第二小节里讨论

1.1 AddRange()

批量新增数据。通过将多个实体标记为 Added 状态,调用 SaveChanges() 时会将这些实体插入到数据库中。
有异步的AddRangeAsync()方法

var student1st = new Student
{Name = "王学生",Age = 18,ClassId = 3
};
var student2sd = new Student
{Name = "李学生",Age = 18,ClassId = 3
};
List<Student> students = new List<Student>()
{student1st,student2sd
};
await dbContext.AddRangeAsync(students);
dbContext.SaveChanges();

1.2 UpdateRange()

批量修改数据。通过将多个实体标记为 Modified 状态,调用 SaveChanges() 时会将这些实体更新到数据库中。

var student1st = await dbContext.Students.FindAsync(21);
var student2sd = await dbContext.Students.FindAsync(22);
student1st.Name = "王学生(新)";
student2sd.Name = "李学生(新)";
List<Student> students = new List<Student>()
{student1st,student2sd
};
dbContext.UpdateRange(students);
dbContext.SaveChanges();

执行结果

info: 5/29/2025 14:40:10.904 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (34ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SELECT TOP(1) [t].[Id], [t].[Age], [t].[ClassId], [t].[Name]FROM [T_Student] AS [t]WHERE [t].[Id] = @__p_0
info: 5/29/2025 14:40:10.957 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (5ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SELECT TOP(1) [t].[Id], [t].[Age], [t].[ClassId], [t].[Name]FROM [T_Student] AS [t]WHERE [t].[Id] = @__p_0
info: 5/29/2025 14:40:11.024 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (13ms) [Parameters=[@p3='?' (DbType = Int32), @p0='?' (DbType = Int32), @p1='?' (DbType = Int32), @p2='?' (Size = 450), @p7='?' (DbType = Int32), @p4='?' (DbType = Int32), @p5='?' (DbType = Int32), @p6='?' (Size = 450)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;UPDATE [T_Student] SET [Age] = @p0, [ClassId] = @p1, [Name] = @p2OUTPUT 1WHERE [Id] = @p3;UPDATE [T_Student] SET [Age] = @p4, [ClassId] = @p5, [Name] = @p6OUTPUT 1WHERE [Id] = @p7;

我们观察到生成的SQL语句分别是三条,前两条是查询指定的学生语句,最后一句才是批量更新。

我们知道EF Core是通过更新实体的状态来生成对应的语句,那么是不是通过人为来指定实体状态,对一个已存在的实体进行批量操作呢
这便是接下来要介绍的AttachRange

1.3 AttachRange()

批量附加数据。AttachRange的用法有些特殊,其核心作用是让 EF Core 开始跟踪一组实体,而不会自动将它们标记为需要插入、更新或删除。如果已存在于数据库中,将多个实体的状态设置为 Unchanged。如果是新实体,这设置为 Added。
该方法源自Attach,Attach方法主要目的就是把一个没有被dbContext跟踪的对象附加到dbCotext中使其被dbContext跟踪

1.1 中我们添加了两个学生,接下来我们手动创建包含这两个学生的List并批量附加到DbSet上。最后修改并批量更新一下这个List集合,观察会发生什么。

List<Student> students = new List<Student>
{new Student{Id = 23,Name = "王学生",Age = 18,ClassId = 3},new Student{Id = 24,Name = "李学生",Age = 18,ClassId = 3}
};
dbContext.Students.AttachRange(students);
students.Where(e => e.Id == 23).FirstOrDefault().Name = "王学生(新)";
students.Where(e => e.Id == 24).FirstOrDefault().Name = "李学生(新)";
dbContext.UpdateRange(students);
dbContext.SaveChanges();

执行结果

info: 5/29/2025 14:53:06.536 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (36ms) [Parameters=[@p3='?' (DbType = Int32), @p0='?' (DbType = Int32), @p1='?' (DbType = Int32), @p2='?' (Size = 450), @p7='?' (DbType = Int32), @p4='?' (DbType = Int32), @p5='?' (DbType = Int32), @p6='?' (Size = 450)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;UPDATE [T_Student] SET [Age] = @p0, [ClassId] = @p1, [Name] = @p2OUTPUT 1WHERE [Id] = @p3;UPDATE [T_Student] SET [Age] = @p4, [ClassId] = @p5, [Name] = @p6OUTPUT 1WHERE [Id] = @p7;

比起1.2里的UpdateRange执行日志里的不同,这里并没有生成查询语句。只有一条批量更新语句。也就是说如果在特定的这种我们知道数据库数据对象的情况下,是可以通过AttachRange操作直接将数据对象附加到实体上去更新。常见于对从缓存中获取数据的操作。

1.4 RemoveRange()

批量删除数据。通过将多个实体标记为 Deleted 状态,调用 SaveChanges() 时会从数据库中删除这些实体。调用 SaveChanges() 时会将这些实体从数据库中删除。

var student1st = await dbContext.Students.FindAsync(23);
var student2sd = await dbContext.Students.FindAsync(24);
List<Student> students = new List<Student>()
{student1st,student2sd
};
dbContext.RemoveRange(students);
dbContext.SaveChanges();

二、Range操作的底层优化

2.1 EF Core 7 前举步维艰

在EF Core 6的版本,我们尝试调用AddRangeAsync()。批量添加一批数据。
EF Core 6 AddRangeAsync代码如下

var student1st = new Student
{Name = "王学生",Age = 18,ClassId = 3
};
var student2nd = new Student
{Name = "李学生",Age = 18,ClassId = 3
};
await dbContext.AddRangeAsync(student1st,student2sd);
dbContext.SaveChanges();

执行结果

info: 5/29/2025 11:16:17.840 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (49ms) [Parameters=[@p0='?' (DbType = Int32), @p1='?' (DbType = Int32), @p2='?' (Size = 450)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;INSERT INTO [T_Student] ([Age], [ClassId], [Name])VALUES (@p0, @p1, @p2);SELECT [Id]FROM [T_Student]WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 5/29/2025 11:16:17.859 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (1ms) [Parameters=[@p0='?' (DbType = Int32), @p1='?' (DbType = Int32), @p2='?' (Size = 450)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;INSERT INTO [T_Student] ([Age], [ClassId], [Name])VALUES (@p0, @p1, @p2);SELECT [Id]FROM [T_Student]WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

通过执行日志里的SQL信息,我们能清晰的观察到,EF Core 6的版本是将student1st, student2nd 分别用两行语句发送给数据库执行。包括UpdateRange(),RemoveRange()。这也是大家对EF Core的批量更新抱怨已久的由来。
EF Core 6的RemoveRange也是生成一个个独立的删除语句
EF Core 6 RemoveRange代码如下

var student1st = await dbContext.Students.FindAsync(21);
var student2sd = await dbContext.Students.FindAsync(22);
dbContext.Students.RemoveRange(student1st, student2sd);
dbContext.SaveChanges();

执行结果

info: 5/29/2025 13:38:10.774 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (28ms) [Parameters=[@p0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;DELETE FROM [T_Student]WHERE [Id] = @p0;SELECT @@ROWCOUNT;
info: 5/29/2025 13:38:10.778 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (1ms) [Parameters=[@p0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SET NOCOUNT ON;DELETE FROM [T_Student]WHERE [Id] = @p0;SELECT @@ROWCOUNT;

执行日志里的SQL信息显示出现了两条删除语句,这点和AddRangeAsync类似。

2.2 EF Core 7后焕然一新

但是这一切在EF Core 7.0 里不一样了。EF Core团队改进了批量操作的执行策略,在添加大量实体时,会智能分组并批量提交 SQL 语句,而不是逐条执行。减少跟踪实体时的内存开销,避免在处理大量数据时出现内存溢出。
我们还是尝试调用AddRangeAsync()和RemoveRange()。批量添加一批数据并删除,观察EF Core 7的底层执行有何不同。
EF Core 7 AddRangeAsync代码如下

var student1st = new Student
{Name = "王学生",Age = 18,ClassId = 3
};
var student2sd = new Student
{Name = "李学生",Age = 18,ClassId = 3
};
await dbContext.AddRangeAsync(student1st, student2sd);
dbContext.SaveChanges();

执行结果

info: 5/29/2025 14:08:50.013 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (89ms) [Parameters=[@p0='?' (DbType = Int32), @p1='?' (DbType = Int32), @p2='?' (Size = 450), @p3='?' (DbType = Int32), @p4='?' (DbType = Int32), @p5='?' (Size = 450)], CommandType='Text', CommandTimeout='30']SET IMPLICIT_TRANSACTIONS OFF;SET NOCOUNT ON;MERGE [T_Student] USING (VALUES (@p0, @p1, @p2, 0),(@p3, @p4, @p5, 1)) AS i ([Age], [ClassId], [Name], _Position) ON 1=0WHEN NOT MATCHED THENINSERT ([Age], [ClassId], [Name])VALUES (i.[Age], i.[ClassId], i.[Name])OUTPUT INSERTED.[Id], i._Position;

而EF Core 7后,执行AddRangeAsync后生成的日志信息里只生成了一行SQL语句。这才是批量更新该有的样子嘛。RemoveRange和其他批量操作同理 ,7.0版本的EF Core都会帮我们优化生成搞笑的SQL语句来执行。

三、无跟踪的批量更新与删除

EF Core 7.0 中已引入两个方法,ExecuteUpdate 和 ExecuteDelete。无需使用 EF 的传统更改跟踪和 SaveChanges() 方法,是无跟踪的批量更新与删除。下面分别介绍二者。

目前仅支持更新和删除;批量新增必须通过 DbSet< TEntity>.AddRange 和 SaveChanges() 完成插入。详细用法在第一小节有介绍。

3.1 ExecuteUpdate

前面我们了解到ExecuteUpdate 没有使用 EF 的传统更改跟踪。也就是说与不会先将数据加载到内存中,而是直接在数据库中执行更新操作,这使得它在处理大量数据时非常高效。
我们试着将查出来的数据,批量更新其中的两个属性。
批量更新——ExecuteUpdate

int[] studentIds =
{23,24
};
var students =   dbContext.Students.Where(e => studentIds.Contains(e.Id));
await students.ExecuteUpdateAsync(s => s.SetProperty(u => u.Name, u => u.Name + "(新)").SetProperty(u => u.Age, u => u.Age + 1)
);

执行结果

info: 5/30/2025 11:11:25.332 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (52ms) [Parameters=[], CommandType='Text', CommandTimeout='30']UPDATE [t]SET [t].[Age] = [t].[Age] + 1,[t].[Name] = [t].[Name] + N'()'FROM [T_Student] AS [t]WHERE [t].[Id] IN (23, 24)

执行结果的日志里我们观察到只有一行update语句,并没有先查询的SQL语句。

3.2 ExecuteDelete

ExecuteDelete和ExecuteUpdate 类似,也没有使用 EF 的传统更改跟踪。在执行删除的时候不会先将数据加载到内存中。

int[] studentIds =
{23,24
};
var students =   dbContext.Students.Where(e => studentIds.Contains(e.Id));
await students.ExecuteDeleteAsync();

执行结果

info: 5/30/2025 11:24:35.693 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (60ms) [Parameters=[], CommandType='Text', CommandTimeout='30']DELETE FROM [t]FROM [T_Student] AS [t]WHERE [t].[Id] IN (23, 24)

执行结果的日志里我们观察到只有一行delete语句,并没有先查询的SQL语句。

3.3 状态冲突

非常重要的一点是,当调用 ExecuteUpdate 且在数据库中更新时,EF 的更改跟踪器不会更新,并且跟踪的实例仍具有其原始值。
我们通过混合使用SaveChanges和ExecuteUpdate举例。

假设学生的年龄最初为 18;执行ExecuteUpdate更新后,数据库中的学生的年龄为19,而跟踪的实体实例中的年龄还是18。 调用 SaveChanges 时,如果再在原来年龄的基础上加一,EF 检测到新值 19 与原始值 18 不同,并保留该更改,最终保存到数据库的年龄还是19。 由 ExecuteUpdate 执行的更改将被覆盖且不考虑在内。

这是一种特殊情况,如果查询的是多条数据,并且对这个IQueryable对象遍历了,这会触发EF Core懒加载的执行,触发数据库查询的执行。这样查出来的结果就是更新后的数据。

int[] studentIds =
{25,26
};
var students =  await dbContext.Students.FirstOrDefaultAsync(e => e.Id == 25);//先执行ExecuteUpdateAsync
await dbContext.Students.ExecuteUpdateAsync(s => s.SetProperty(u => u.Age, u => u.Age + 1)
);//再执行实体追踪的批量更新
students.Age += 2;
await dbContext.SaveChangesAsync();

执行结果

info: 5/30/2025 11:42:37.335 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (44ms) [Parameters=[], CommandType='Text', CommandTimeout='30']SELECT TOP(1) [t].[Id], [t].[Age], [t].[ClassId], [t].[Name]FROM [T_Student] AS [t]WHERE [t].[Id] = 25
info: 5/30/2025 11:42:37.446 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (15ms) [Parameters=[], CommandType='Text', CommandTimeout='30']UPDATE [t]SET [t].[Age] = [t].[Age] + 1FROM [T_Student] AS [t]
info: 5/30/2025 11:42:37.553 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)Executed DbCommand (34ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']SET IMPLICIT_TRANSACTIONS OFF;SET NOCOUNT ON;UPDATE [T_Student] SET [Age] = @p0OUTPUT 1WHERE [Id] = @p1;

因此,通常最好避免通过实体追踪更新数据SaveChanges的方式 与 ExecuteUpdate无跟踪更新数据的方式混用


总结

本文对比了 EF Core 7 前后批量操作(如 AddRange/RemoveRange)的底层实现差异,介绍了 AttachRange 的特殊用法,并重点解析了无跟踪批量更新 ExecuteUpdate 和删除 ExecuteDelete 的原理与状态冲突问题。

相关文章:

【EF Core】 EF Core 批量操作的进化之路——从传统变更跟踪到无跟踪更新

文章目录 前言一、批量操作&#xff08;Rang&#xff09;1.1 AddRange()1.2 UpdateRange()1.3 AttachRange()1.4 RemoveRange() 二、Range操作的底层优化2.1 EF Core 7 前举步维艰2.2 EF Core 7后焕然一新 三、无跟踪的批量更新与删除3.1 ExecuteUpdate3.2 ExecuteDelete3.3 状…...

[Go] Option选项设计模式 — — 编程方式基础入门

[Go] Option选项设计模式 — — 编程方式基础入门 全部代码地址&#xff0c;欢迎⭐️ Github&#xff1a;https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-option 1 介绍 在 Go 开发中&#xff0c;我们经常遇到需要处理多参数配置的场景。传统方…...

Vue 项目命名规范指南

&#x1f4da; Vue 项目命名规范指南&#xff08;适用于 Vue 3 Pinia Vue Router&#xff09; 目的&#xff1a;统一命名风格&#xff0c;提升可读性、可维护性和团队协作效率。 一、通用原则 类型命名风格示例变量camelCaseuserName, isLoading常量UPPER_SNAKE_CASEMAX_RET…...

【笔记】开源通用人工智能代理 Suna 部署全流程准备清单(Windows 系统)

#工作记录 一、基础工具与环境 开发工具 Git 或 GitHub Desktop&#xff08;代码管理&#xff09;Docker Desktop&#xff08;需启用 WSL2&#xff0c;容器化部署&#xff09;Python 3.11&#xff08;推荐版本&#xff0c;需添加到系统环境变量&#xff09;Node.js LTS&#xf…...

海康工业相机SDK二次开发(VS+QT+海康SDK+C++)

前言 工业相机在现代制造和工业自动化中扮演了至关重要的角色&#xff0c;尤其是在高精度、高速度检测中。海康威视工业相机以其性能稳定、图像质量高、兼容性强而受到广泛青睐。特别是搞机器视觉的小伙伴们跟海康打交道肯定不在少数&#xff0c;笔者在平常项目中跟海康相关人…...

前端面试准备-5

1.Node.js中的process.nectTick()有什么作用 将一个回调函数插入到当前执行栈的尾部&#xff0c;在下一次事件轮询之前调用这个回调函数 2.什么是Node.js中的事件发射器&#xff0c;作用是什么&#xff0c;如何使用 提供一种机制&#xff0c;可以创建、触发和监听自定义事件…...

Spring Boot 启动流程深度解析:从源码到实践

Spring Boot 启动流程深度解析&#xff1a;从源码到实践 Spring Boot 作为 Java 开发的主流框架&#xff0c;其 “约定大于配置” 的理念极大提升了开发效率。本文将从源码层面深入解析 Spring Boot 的启动流程&#xff0c;并通过代码示例展示其工作机制。 一、Spring Boot 启…...

深度学习|pytorch基本运算-乘除法和幂运算

【1】引言 前序学习进程中&#xff0c;已经对pytorch张量数据的生成和广播做了详细探究&#xff0c;文章链接为&#xff1a; 深度学习|pytorch基本运算-CSDN博客 深度学习|pytorch基本运算-广播失效-CSDN博客 上述探索的内容还止步于张量的加减法&#xff0c;在此基础上&am…...

嵌入式通用集成电路卡市场潜力报告:物联网浪潮下的机遇与挑战剖析

一、嵌入式通用集成电路卡概述​ 嵌入式通用集成电路卡&#xff08;Embedded Universal Integrated Circuit Card&#xff0c;简称 eUICC&#xff09;&#xff0c;是一种将传统 SIM 卡功能直接嵌入到设备主板上的芯片解决方案 。与传统可插拔式 SIM 卡不同&#xff0c;eUICC 采…...

4.2.4 Spark SQL 数据写入模式

在本节实战中&#xff0c;我们详细探讨了Spark SQL中数据写入的四种模式&#xff1a;ErrorIfExists、Append、Overwrite和Ignore。通过具体案例&#xff0c;我们演示了如何使用mode()方法结合SaveMode枚举类来控制数据写入行为。我们首先读取了一个JSON文件生成DataFrame&#…...

论文笔记: Urban Region Embedding via Multi-View Contrastive Prediction

AAAI 2024 1 INTRO 之前基于多视图的region embedding工作大多遵循相同的模式 单独的单视图表示多视图融合 但这种方法存在明显的局限性&#xff1a;忽略了不同视图之间的信息一致性 一个区域的多个视图所携带的信息是高度相关的&#xff0c;因此它们的表示应该是一致的如果能…...

Android 缓存应用冻结器(Cached Apps Freezer)

一、核心功能与原理 1. 功能概述 目标&#xff1a;通过冻结后台缓存应用的进程&#xff0c;减少其对 CPU、内存等系统资源的消耗&#xff0c;优化设备性能与续航。适用场景&#xff1a;针对行为不当的后台应用&#xff08;如后台偷偷运行代码、占用 CPU&#xff09;&#xff…...

初学者如何微调大模型?从0到1详解

本文将手把手带你从0到1&#xff0c;详细解析初学者如何微调大模型&#xff0c;让你也能驾驭这些强大的AI工具。 1. 什么是大模型微调&#xff1f; 想象一下&#xff0c;预训练大模型就像一位博览群书但缺乏专业知识的通才。它掌握了海量的通用知识&#xff0c;但可能无法完美…...

西瓜书第十一章——降维与度量学习

文章目录 降维与度量学习k近邻学习原理头歌实战-numpy实现KNNsklearn实现KNN 降维——多维缩放&#xff08;Multidimensional Scaling, MDS&#xff0c;MDS&#xff09;提出背景与原理重述1.**提出背景**2.**数学建模与原理推导**3.**关键推导步骤** Principal Component Analy…...

Portainer安装指南:多节点监控的docker管理面板-家庭云计算专家

背景 Portainer 是一个轻量级且功能强大的容器管理面板&#xff0c;专为 Docker 和 Kubernetes 环境设计。它通过直观的 Web 界面简化了容器的部署、管理和监控&#xff0c;即使是非技术用户也能轻松上手。Portainer 支持多节点管理&#xff0c;允许用户从一个中央控制台管理多…...

NanoGPT的BenchMarking.py

1.Benchmarking是一种评估和比较性能的过程。在深度学习领域&#xff0c;它通常涉及对模型的训练速度、推理速度、内存占用等指标进行测量&#xff0c;以便评估不同模型、不同硬件配置或者不同软件版本之间的性能差异。 例如&#xff0c;当你尝试比较两个不同架构的模型&#x…...

测试用例及黑盒测试方法

一、测试用例 1.1 基本要素 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等4个主要要素。 1.1.1 测试环境 定义&#xff1a;测试执行所需的软硬件…...

CentOS 7 环境下部署 LAMP

在 CentOS 7 环境下部署 LAMP&#xff08;Linux Apache MySQL 5.7 PHP 7.4&#xff09; 环境的详细步骤如下&#xff1a; 1. 系统准备 1.1 更新系统 sudo yum update -y 1.2 安装依赖 sudo yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel e…...

vscode实用配置

前端开发安装插件&#xff1a; 1.可以更好看的显示文件图标 2.用户快速打开文件 使用步骤&#xff1a;在html文件下右键点击 open with live server 即可 刷力扣&#xff1a; 安装这个插件 还需要安装node.js即可...

React 项目中封装 Excel 导入导出组件:技术分享与实践

文章目录 前言一、为什么需要封装 Excel 组件&#xff1f;二、技术选型三、核心实现1. 安装依赖2. 封装Excel导出3. 封装导入组件 &#xff08;UploadExcel&#xff09; 总结 前言 在 React 项目中&#xff0c;处理 Excel 文件的导入和导出是常见的业务需求。无论是导出报表数…...

【PhysUnits】15.1 引入P1后的加一特质(add1.rs)

一、源码 代码实现了类型系统中的"加一"操作&#xff08;Add1 trait&#xff09;&#xff0c;用于在编译期进行数字的增量计算。 //! 加一操作特质实现 / Increment operation trait implementation //! //! 说明&#xff1a; //! 1. Z0、P1,、N1 1&#xff0…...

【2025CCF中国开源大会】RISC-V 开源生态的挑战与机遇分论坛重磅来袭!共探开源芯片未来

点击蓝字 关注我们 CCF Opensource Development Committee 开源浪潮正从软件席卷硬件领域&#xff0c;RISC-V作为全球瞩目的开源芯片架构&#xff0c;正在重塑计算生态的版图&#xff01;相较于成熟的x86与ARM&#xff0c;RISC-V生态虽处爆发初期&#xff0c;却蕴藏着无限可能。…...

python完成批量复制Excel文件并根据另一个Excel文件中的名称重命名

import openpyxl import shutil import os # 原始文件路径 original_file "C:/Users/Administrator/Desktop/事业联考面试名单/郑州.xlsx" # 读取包含名称的Excel文件 # 修改为您的文件名 wb openpyxl.load_workbook( "C:/Users/Administrator/Desktop/事…...

Vue-2-前端框架Vue基础入门之二

文章目录 1 计算属性1.1 计算属性简介1.2 计算属性示例 2 侦听器2.1 简单的侦听器2.2 深度监听2.3 监听对象单个属性 3 vue-cli3.1 工程化的Vue项目3.2 Vue项目的运行流程 4 vue组件4.1 Vue组件的三个部分4.1.1 template4.1.2 script4.1.3 style 4.2 组件之间的关系4.2.1 使用组…...

CPT208 Human-Centric Computing 人机交互 Pt.7 交互和交互界面

文章目录 1. 界面隐喻&#xff08;Interface metaphors&#xff09;1.1 界面隐喻的应用方式1.2 界面隐喻的优缺点 2. 交互类型2.1 Instructing&#xff08;指令式交互&#xff09;2.2 Conversing&#xff08;对话式交互&#xff09;2.3 Manipulating&#xff08;操作式交互&…...

ubuntu20.04.5-arm64版安装robotjs

ubuntu20.04.5arm上使用robotjs #ssh&#xff0c;可选 sudo apt update sudo apt install openssh-server sudo systemctl status ssh sudo systemctl enable ssh sudo systemctl enable --now ssh #防火墙相关&#xff0c;可选 sudo ufw allow ssh sudo ufw allow 2222/tc…...

[网页五子棋][匹配模块]前后端交互接口(消息推送机制)、客户端开发(匹配页面、匹配功能)

让多个用户&#xff0c;在游戏大厅中能够进行匹配&#xff0c;系统会把实力相近的两个玩家凑成一桌&#xff0c;进行对战 约定前后端交互接口 消息推送机制 匹配这样的功能&#xff0c;也是依赖消息推送机制的 玩家 1 点击开始匹配按钮&#xff0c;就会告诉服务器&#xff1…...

【数据分析】Matplotlib+Pandas+Seaborn绘图

【数据分析】MatplotlibPandasSeaborn绘图 &#xff08;一&#xff09;Matplotlib绘图1.1 matplotlib绘图方式1: 状态接口1.2 matplotlib绘图方式2: 面向对象1.3 通过安斯科姆数据集, 说明可视化的重要性1.4 MatPlotlib绘图-单变量-直方图1.5 MatPlotlib绘图-双变量-散点图1.6 …...

NLP学习路线图(十五):TF-IDF(词频-逆文档频率)

在自然语言处理&#xff08;NLP&#xff09;的浩瀚宇宙中&#xff0c;TF-IDF&#xff08;词频-逆文档频率&#xff09; 犹如一颗恒星&#xff0c;虽古老却依然璀璨。当ChatGPT、BERT等大模型光芒四射时&#xff0c;TF-IDF作为传统方法的代表&#xff0c;其简洁性、高效性与可解…...

[Redis] Redis命令在Pycharm中的使用

初次学习&#xff0c;如有错误还请指正 目录 String命令 Hash命令 List命令 set命令 SortedSet命令 连接pycharm的过程见&#xff1a;[Redis] 在Linux中安装Redis并连接桌面客户端或Pycharm-CSDN博客 redis命令的使用见&#xff1a;[Redis] Redis命令&#xff08;1&#xf…...