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

02020506 EF Core高级06-EF Core批量删除更新插入、全局筛选器、软删除、全局筛选的性能问题

02020506 EF Core高级06-EF Core批量删除&更新&插入、全局筛选器、软删除、全局筛选的性能问题

1. EF Core如何批量删除、更新、插入(视频3-36)

1.1 EF Core中插入数据(单条)
1、EF Core中不支持高效的删除、更新、插入数据,都是逐条操作。AddRange、DeleteRange等。
2、理想的:Delete from T_Books where Price>33
3、看看ctx.RemoveRange(ctx.Books.Where(b=> b.Price > 33))、 AddRange、批量更新等内部是怎么实现的。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// EF Core插入数据形式1
using (MyDbContext ctx = new MyDbContext())
{Article a01 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a02 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a03 = new Article { Message = "abc", Price = 10, Title = "ABC" };ctx.Articles.Add(a01);ctx.Articles.Add(a02);ctx.Articles.Add(a03);
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// EF Core插入数据形式2
using (MyDbContext ctx = new MyDbContext())
{Article a01 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a02 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a03 = new Article { Message = "abc", Price = 10, Title = "ABC" };ctx.Articles.AddRange(a01, a02, a03);
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// EF Core插入数据形式3
using (MyDbContext ctx = new MyDbContext())
{Article a01 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a02 = new Article { Message = "abc", Price = 10, Title = "ABC" };Article a03 = new Article { Message = "abc", Price = 10, Title = "ABC" };ctx.AddRange(a01, a02, a03);
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:
1. 上述三种写法在EF Core中对数据库的操作是一样的,但这还是属于EF Core中数据一条条的插入。
2. AddRange方法知识用了for循环一条条的插入,也并不是一次性插入多条数据。
3. 在数据库中还是执行了三条insert语句。如果插入一万条呢?那么会有一万条insert,这样会造成性能损失。
1.2 EF Core中删除数据(单条)
// EF Core删除数据形式1
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){foreach (var item in ctx.Articles.Where(a => a.Id > 20)){ctx.Remove(item);}ctx.SaveChanges();}Console.WriteLine();}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){ctx.RemoveRange(ctx.Articles.Where(a => a.Id > 1));ctx.SaveChanges();}Console.WriteLine();}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:上述两种写法在EF Core中对数据库的操作是一样的,但这还是属于EF Core中数据一条条的删除。

2. 为啥不用原生SQL实现

2.1 使用原生SQL的缺点
1、原生SQL语句需要把表名、列名等硬编码到SQL语句中,不符合模型驱动、分层隔离等思想,程序员直接面对数据库表,无法利用EF Core强类型的特性,如果模型发生改变,必须手动变更SQL语句。
1.1 如update t set Price = Price + 1
1.2 如delete from t where Id > 10
2、无法利用EF Core强大的SQL翻译机制来屏蔽不同底层数据库的差异。
3、EF Core官方迟迟未支持的原因。
2.2 微软官方关于此处的探讨
  • https://github.com/dotnet/efcore/issues/795
2.3 老师的开源实现
1、Zack.EFCore.Batch
2、await ctx.DeleteRangeAsync<Book>(b => b.Price > n || b.AuthorName =="zack yang");
await ctx.BatchUpdate<Book>().Set(b => b.Price, b => b.Price + 3).Set(b => b.Title, b => s).Set(b =>b.AuthorName,b=>b.Title.Substring(3,2)+b.AuthorName.ToUpper()).Set(b => b.PubTime, b => DateTime.Now).Where(b => b.Id > n || b.AuthorName.StartsWith("Zack")).ExecuteAsync();
ctx.BulkInsert(books);
2.4 Zack.EFCore.Batch包使用
  • 以Zack.EFCore.Batch -version 1.4.6示例
  • 官方文档:https://github.com/yangzhongke/Zack.EFCore.Batch

3. EF Core全局查询筛选器(视频3-37)

3.1 全局查询筛选器概述
1、全局查询筛选器:EF Core 会自动将这个查询筛选器应用于涉及这个实体类型的所有 LINQ 查询。
2、场景:软删除、多租户。
3.2 什么是软删除
图片链接丢失
delete from t where Name = "张三" // 直接从数据库删除,无法恢复,属于硬删除。增加IsDeleted列,为true表示屏蔽,为false表示未屏蔽,这样可以追溯。
3.3 软删除的用法示例一
  • 在在02020503章4.5节基础上继续
1、builder.HasQueryFilter(b=>b.IsDeleted==false);
2、测试一下如下的代码,查看生成的SQL:
ctx.Books.Where(b=>b.Price>20).ToArray()
3、忽略:ctx.Books.IgnoreQueryFilters().Where(b => b.Title.Contains("o")).ToArray()
查看SQL
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Article.cs
using System.Collections.Generic;namespace OneToMany
{class Article // 文章{public long Id { get; set; }public string Title { get; set; }public string Message { get; set; }public List<Comment> Comments { get; set; } = new List<Comment>();public int Price { get; set; }public bool IsDeleted { get; set; } // 增加状态列}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 迁移数据库之前
Id	Title	Message	Price	
1	杨中科入选中科院	大新闻	30
577	ABC	abc	10
578	ABC	abc	10
579	ABC	abc	10
580	ABC	abc	10
581	ABC	abc	10
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 迁移数据库
PM> add-migration isdeleted
Build started...
Build succeeded.
The Entity Framework tools version '5.0.4' is older than that of the runtime '5.0.5'. Update the tools for the latest features and bug fixes.
To undo this action, use Remove-Migration.
PM> update-database
Build started...
Build succeeded.
The Entity Framework tools version '5.0.4' is older than that of the runtime '5.0.5'. Update the tools for the latest features and bug fixes.
Applying migration '20251006023435_isdeleted'.
Done.
PM> 
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 迁移数据库之后
Id	Title	Message	Price	IsDeleted
1	杨中科入选中科院	大新闻	30	0
577	ABC	abc	10	0
578	ABC	abc	10	0
579	ABC	abc	10	0
580	ABC	abc	10	0
581	ABC	abc	10	0
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){foreach (var item in ctx.Articles){Console.WriteLine(item.Id + item.Price);}}Console.WriteLine();}}
}控制台输出:
31
587
588
589
590
591
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){var a = ctx.Articles.Single(a => a.Id == 1);a.IsDeleted = true;ctx.SaveChanges();}Console.WriteLine();}}
}// 此时数据库状态:
Id	Title	Message	Price	IsDeleted
1	杨中科入选中科院	大新闻	30	1 // 状态已经更新
577	ABC	abc	10	0
578	ABC	abc	10	0
579	ABC	abc	10	0
580	ABC	abc	10	0
581	ABC	abc	10	0
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using System;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){foreach (var item in ctx.Articles) // 查询所有{Console.WriteLine(item.Id + item.Price);}Console.WriteLine("********************");foreach (var item in ctx.Articles.Where(a => a.IsDeleted == false)) // 依据IsDeleted来查询{Console.WriteLine(item.Id + item.Price);}}Console.WriteLine();}}
}控制台输出:
31
587
588
589
590
591
********************
587
588
589
590
591// SQL语句1
SELECT [t].[Id], [t].[IsDeleted], [t].[Message], [t].[Price], [t].[Title]FROM [T_Articles] AS [t]********************
// SQL语句2
SELECT t.Id, t.IsDeleted, t.Message, t.Price, t.TitleFROM T_Articles AS tWHERE t.IsDeleted == CAST(0 AS bit)),说明:SQL语句2增加了IsDeleted过滤
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
总结:每一次都要使用IsDeleted比较麻烦,可以使用全局筛选器来实现。
3.4 软删除的用法示例二
// ArticleConfig.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;namespace OneToMany
{class ArticleConfig : IEntityTypeConfiguration<Article>{public void Configure(EntityTypeBuilder<Article> builder){builder.ToTable("T_Articles");builder.Property(a => a.Title).HasMaxLength(100).IsUnicode().IsRequired();builder.Property(a => a.Message).IsUnicode().IsRequired();builder.HasQueryFilter(a => a.IsDeleted == false); // 增加筛选}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 使用全局过滤器
using System;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){foreach (var item in ctx.Articles) // 查询所有,但是已经屏蔽了Id为1的数据项{Console.WriteLine(item.Id + item.Price);}}Console.WriteLine();}}
}控制台输出:
587
588
589
590
591// SQL语句
SELECT [t].[Id], [t].[IsDeleted], [t].[Message], [t].[Price], [t].[Title]FROM [T_Articles] AS [t]WHERE [t].[IsDeleted] <> CAST(1 AS bit)说明:自动增加了IsDeleted过滤。
3.5 软删除的用法示例三
// 忽略全局过滤器
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;namespace OneToMany
{class Program{static async Task Main(string[] args){using (MyDbContext ctx = new MyDbContext()){foreach (var item in ctx.Articles.IgnoreQueryFilters()) // 忽略全局过滤器{Console.WriteLine(item.Id + item.Price);}}Console.WriteLine();}}
}控制台输出:
31
587
588
589
590
591// 查看SQLSELECT [t].[Id], [t].[IsDeleted], [t].[Message], [t].[Price], [t].[Title]FROM [T_Articles] AS [t]说明:忽略了IsDeleted过滤。
3.6 全局筛选的性能问题
  • 可以通过索引或者其它方面的优化,遇到了再来解决。
  • 傻瓜化的功能代表开发的时候不用关心细节问题,但不代表开发人员不需要知道相关知识点。
  • 开发人员可以尽情享受傻瓜化的功能,但是遇到问题你要知道所以然。

结尾

书籍:ASP.NET Core技术内幕与项目实战

视频:https://www.bilibili.com/video/BV1pK41137He

著:杨中科

ISBN:978-7-115-58657-5

版次:第1版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

http://www.hskmm.com/?act=detail&tid=28955

相关文章:

  • 机器学习社会影响与导航系统研究
  • ubuntu24.04 desktop 安装vnc远程桌面(亲测)
  • 完整教程:游标查询在对话历史场景下的独特优势
  • [论文笔记] A Contemporary Survey of Large Language Model Assisted Program Analysis
  • 251011
  • 一种整理HTML和JS代码的方法
  • 元推理框架,是人类文明的《神农本草经》,源于自指自洽的觉悟与洗礼
  • SSL/TLS加密算法:守护网络通信的安全框架
  • 未来计划
  • 【程序员必看】MySQL数据类型全解析:选错类型性能直接掉80%!
  • NOIP2023
  • 理解WPF Stylet中Command=“{s:Action 方法名}“的设计与实现 - 实践
  • 2025环氧地坪漆厂家推荐:常州新禾,品质保证施工无忧!
  • 概率论习题
  • 2025上海经侦律师TOP5榜单:专业法律服务与高效解决方案
  • 概率论部分习题
  • 2025家居ERP推荐:赛思软件助力企业高效管理!
  • 2025彩钢瓦保养优质厂家推荐,江苏承优建筑工程专业服务!
  • 优维科技一面
  • 2025家纺摄影公司最新推荐榜:创意视觉与专业服务的完美结合
  • 2025磁力泵加工厂推荐中正化工,专业定制高效耐用产品!
  • 线段树分治
  • 2025双氧水供应厂家推荐:苏州市岚昱化工品质卓越选择!
  • 2025婚纱照拍摄推荐,南通造物摄影有限公司专业团队打造梦幻
  • 2025上海保洁公司最新推荐榜:高效清洁与贴心服务的优质选择
  • 10.11
  • 「解题报告」蓝桥杯2013省AB 错误票据
  • 2025精密弹簧优质厂家推荐:蓝侨盈科技,精准弹性解决方案!
  • 时时想起 寸步难行 叩问自己 无人回应 若我离去 若我死去 枯萎于这幽暗的井底 长眠不醒
  • 有限空间作业安全无死角!AI 视觉守护人员与操作合规