C#怎么实现EF Core软删除 C#如何用EF Core全局过滤器实现数据软删除和逻辑删除【数据库】

穿越時空

穿越時空

2026-03-30

922人浏览

原创

ef core软删除必须通过hasqueryfilter配置全局查询过滤器并配合拦截savechanges实现逻辑删除。需为实体显式配置isdeleted字段的过滤条件,重写删除行为为更新操作,必要时用ignorequeryfilters绕过过滤,并为isdeleted字段建立索引以保障性能。

c#怎么实现ef core软删除 c#如何用ef core全局过滤器实现数据软删除和逻辑删除【数据库】

EF Core 软删除必须靠 HasQueryFilter 配合字段标记

软删除不是“删数据”,而是让查询自动过滤掉被标记为已删除的记录。EF Core 不提供开箱即用的“软删开关”,核心依赖 HasQueryFilter 在模型配置中注入全局 WHERE 条件。没配这个,哪怕数据库里加了 IsDeleted 字段,查询照样返回所有行。

常见错误现象:context.Users.ToList() 仍查出已“删除”的用户;调用 Remove() 后数据真被物理删了;或者手动写 .Where(x => !x.IsDeleted) 到处都是,漏一处就出问题。

  • 必须在 OnModelCreating 中为每个需软删除的实体显式配置 HasQueryFilter,不能只靠约定
  • 推荐统一使用 bool IsDeleted 字段(而非 DateTime? DeletedAt),避免空值比较引发的 SQL NULL 语义陷阱
  • 如果实体有继承关系(如 AuditEntity 基类),HasQueryFilter 可以写在基类映射里,但子类若重写该属性,需确保类型转换安全

删除操作要重写 SaveChanges 或用拦截器,不能直接 Remove()

EF Core 默认的 Remove() 是物理删除。想实现“点删除变更新”,得拦截保存动作,把 EntityState.Deleted 实体转成 EntityState.Modified 并设置 IsDeleted = true。否则,哪怕配了 HasQueryFilter,数据也早被 DELETE 语句干掉了。

使用场景:管理后台点击“删除用户”,后端 API 接收请求后调用 context.Users.Remove(user) —— 这行代码本身不危险,危险的是紧接着的 SaveChanges()

  • 推荐用 SaveChangesInterceptor(EF Core 5.0+),比重写 SaveChanges 更干净,避免递归调用风险
  • 拦截时只处理状态为 Deleted 且类型实现了软删除接口(如 IHasSoftDelete)的实体
  • 记得清除原 Deleted 状态并设为 Modified,否则 EF 仍会生成 DELETE 语句
  • 注意并发:如果同一实体在拦截前已被其他逻辑标记为 IsDeleted = true,重复设置可能触发无意义更新

IgnoreQueryFilters 是绕过软删除的唯一合法方式,但要用对地方

有些场景确实需要查“全部”,比如回收站页面、后台数据修复、或导出报表。这时不能删 HasQueryFilter,也不能临时改模型配置,唯一正确做法是调用 IgnoreQueryFilters() 方法。

C函数速查手册(CHM版)
C函数速查手册(CHM版)

C函数速查手册(CHM版)

下载

错误用法:context.Users.AsNoTracking().Where(...) 依然受过滤器影响;FromSqlRaw 虽然能绕过,但失去变更跟踪和类型安全,属于退化方案。

  • IgnoreQueryFilters() 必须在 IQueryable 链最前端调用,例如:context.Users.IgnoreQueryFilters().Where(x => x.IsDeleted)
  • 它只对当前查询生效,不影响后续查询,也不改变上下文状态
  • 不要在通用仓储方法里默认加 IgnoreQueryFilters(),否则软删除形同虚设
  • 配合 AsNoTracking() 使用没问题,但两者目的不同:前者关过滤,后者关跟踪

软删除字段必须建索引,否则查询性能会断崖下跌

HasQueryFilter 最终生成的 SQL 是带 WHERE IsDeleted = 0 的,如果表大、IsDeleted 区分度低(比如 95% 数据都已删除),又没索引,全表扫描就来了。线上查个列表卡 3 秒,八成是这原因。

兼容性影响:SQL Server 和 PostgreSQL 对布尔字段索引支持良好;MySQL 5.7 之前不支持函数索引,IsDeleted 字段单独建 B-Tree 索引即可;SQLite 没问题,但别指望它扛高并发。

  • 索引名建议带业务含义,比如 IX_Users_IsDeleted,方便 DBA 识别用途
  • 如果经常按 IsDeleted + CreatedAt 组合查询(如查最近删除的用户),建联合索引更高效
  • 迁移脚本里补索引时,注意生产环境锁表风险,大表优先用 CREATE INDEX CONCURRENTLY(PostgreSQL)或在线索引(SQL Server Enterprise)

软删除看着只是加个字段和一行配置,但查询路径、保存路径、索引策略三者缺一不可。少配一个,轻则数据泄露,重则性能雪崩——尤其当“已删除”数据量反超正常数据时,那个 IsDeleted 字段就从开关变成瓶颈了。

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1111

5

前端如何实现即时通讯
前端如何实现即时通讯

实现即时通讯的方法有WebSocket、Long Polling、Server-Sent Events、WebRTC等等。详细介绍:1、WebSocket,它可以在客户端和服务器之间建立持久连接,实现实时的双向通信,前端可以使用 WebSocket API来创建WebSocket连接,并通过发送和接收消息来实现即时通讯;2、Long Polling,是一种模拟实时通信的技术等等。

2023.10.09

2262

6

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

2130

13

php和前端的关联介绍
php和前端的关联介绍

php既可以作为前端语言,也可以作为后端语言。想了解更多php和前端的相关内容,可以阅读本专题下面的文章。

2024.03.22

2321

10

前端外包工作内容有哪些
前端外包工作内容有哪些

前端外包工作内容包括:1. 网站和应用程序开发;2. 用户界面和交互设计;3. 用户体验优化;4. 设计和视觉开发;5. 跨浏览器兼容性;6. 性能优化;7. 维护和更新;8. 项目管理和沟通。想了解更多前端的相关内容,可以阅读本专题下面的文章。

2024.05.22

336

5

c#是什么意思
c#是什么意思

C#是一种通用的面向对象编程语言,它在.NET框架上运行,可用于开发各种类型的应用程序。本专题为大家提供c#相关的各种文章、以及下载和课程。

2023.08.08

528

5

什么是c#
什么是c#

C#(读作C Sharp)是一种现代的、通用的、面向对象的编程语言。它由微软公司开发,于2000年首次发布,主要用于开发Windows桌面应用程序、Web应用程序、移动应用程序以及游戏开发等领域。C#是一种类型安全和托管的编程语言,它结合了C++的强大性能和C语言的简单易学特点,并引入了许多新的特性和概念,如委托、属性、泛型和异步编程等,以提高开发效率和代码可维护性。

2023.08.31

1160

3

C#中base关键字的用法
C#中base关键字的用法

在C#中,base关键字用于访问当前类的基类成员,这包括基类的字段、属性、方法、构造函数、索引器以及事件。想了解更多C#的相关内容,可以阅读本专题下面的文章。

2024.03.13

556

8

C#Task用法
C#Task用法

Task在C#中是用于表示异步操作的对象,它位于System.Threading.Tasks命名空间中。想了解更多C#中各种用法的相关内容,可以阅读本专题下面的文章。

2024.03.14

1051

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
RabbitMQ 教程手册
RabbitMQ 教程手册

共0课时 | 0人学习

Linux man-pages 项目
Linux man-pages 项目

共0课时 | 0人学习

C# 教程
C# 教程

共94课时 | 20.2万人学习