EF Core软删除核心是用查询过滤器自动屏蔽IsDeleted为true的数据,需添加IsDeleted字段、配置HasQueryFilter、重写SaveChanges将Delete转为Update,并可用IgnoreQueryFilters临时绕过。

EF Core 实现软删除,核心是用 查询过滤器(Query Filter) 自动屏蔽已标记为“删除”的数据,而不是真正从数据库删掉。它不依赖手写 .Where(!x.IsDeleted),而是让每次查询都透明生效——既安全又省心。
加一个 IsDeleted 字段
在要支持软删除的实体类里,添加布尔类型的标记属性:
- 推荐命名为
IsDeleted,类型为bool,默认值设为false - 如果需要记录删除时间或操作人,可额外加
DeletedAt、DeletedBy字段 - 不要对一对一关联实体单独软删除,容易引发导航属性异常
在 DbContext 中配置查询过滤器
重写 OnModelCreating 方法,为实体启用全局过滤:
- 基础写法:
modelBuilder.Entity().HasQueryFilter(p => !p.IsDeleted); - 字段存为整数(如数据库用
TINYINT)?加上值转换:.Property(e => e.IsDeleted).HasConversion() - 多个实体统一处理?可用反射遍历实现
IDeletable接口的类型,自动注册过滤器
覆盖删除行为:把 Delete 变成 Update
调用 Remove() 时,EF 默认会生成 DELETE SQL。要改成软删除,得拦截保存前的操作:
- 重写
SaveChanges和SaveChangesAsync - 遍历
ChangeTracker.Entries(),对EntityState.Deleted的条目改为Modified,并把IsDeleted设为true - 新增数据时确保
IsDeleted默认为false(可在Added分支中设置)
需要查已删除数据?临时绕过过滤器
管理后台或恢复功能常需看到全部记录,这时可以用:
context.Posts.IgnoreQueryFilters().Where(p => p.IsDeleted).ToList()- 注意:
IgnoreQueryFilters()会跳过该实体上所有过滤器,不只是软删除那个 - 如需更灵活控制(比如只在某些场景下包含已删数据),建议构造不同 DbContext 实例,或通过构造函数传入开关参数
基本上就这些。不复杂但容易忽略细节,比如没改 SaveChanges 行为会导致物理删除,或者忘了给关联实体配过滤器导致数据不一致。










