EF Core 实现软删除,核心是用 查询过滤器(Query Filter) 自动屏蔽已标记为“删除”的数据,而不是真正从数据库删掉。它不依赖手写
.Where(!x.IsDeleted),而是让每次查询都透明生效——既安全又省心。
加一个 IsDeleted 字段
在要支持软删除的实体类里,添加布尔类型的标记属性:
推荐命名为IsDeleted,类型为
bool,默认值设为
false如果需要记录删除时间或操作人,可额外加
DeletedAt、
DeletedBy字段 不要对一对一关联实体单独软删除,容易引发导航属性异常
在 DbContext 中配置查询过滤器
重写
OnModelCreating方法,为实体启用全局过滤: 基础写法:
modelBuilder.Entity<post>().HasQueryFilter(p => !p.IsDeleted);</post>字段存为整数(如数据库用
TINYINT)?加上值转换:
.Property(e => e.IsDeleted).HasConversion<int>()</int>多个实体统一处理?可用反射遍历实现
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 行为会导致物理删除,或者忘了给关联实体配过滤器导致数据不一致。
