跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

C#如何实现EFCore全局过滤器_C#软删除IsDeleted自动过滤【核心】

EF Core全局查询过滤器必须在OnModelCreating中用HasQueryFilter注册且仅生效一次,典型软删除写法为modelBuilder.Entity().HasQueryFilter(x => !x.IsDeleted),支持Find、Where、Include等查询,绕过需用IgnoreQueryFilters()。 EF Core 全局查询过滤器怎么加 全局过滤器必须在
OnModelCreating
中通过
modelBuilder.Entity().HasQueryFilter()
注册,且只能注册一次。重复调用会覆盖前一个,不会合并。 软删除场景下,典型写法是:
modelBuilder.Entity().HasQueryFilter(x => !x.IsDeleted);
注意:
IsDeleted
字段必须是实体类的属性(不能是计算字段或导航属性),且类型为
bool
或可空
bool?
;若为
bool?
,需显式处理 null(如
x.IsDeleted != true
)。 过滤器对所有查询生效——包括
FindAsync
、
FirstOrDefault
、
Include
关联查询(但不自动穿透到被 Include 的子实体,除非子实体也单独配置了过滤器) 迁移生成时,EF Core 不会因过滤器自动加索引,建议手动为
IsDeleted
加索引提升性能 若实体有多个软删除状态(如
Deleted
/
Archived
),不能靠一个布尔字段表达,得换用枚举 + 更复杂的表达式,但会增加过滤器维护成本 如何临时绕过全局过滤器查已删除数据 用
IgnoreQueryFilters()
方法可以跳过当前查询的全局过滤逻辑,仅对本次查询生效,不影响其他地方。 常见于后台管理「回收站」页面或数据修复脚本:
var deletedUsers = await context.Users.IgnoreQueryFilters() .Where(x => x.IsDeleted) .ToListAsync();
它只作用于调用它的
IQueryable
链,不会影响后续新建的查询 不能在
AsNoTracking()
之后再调用
IgnoreQueryFilters()
——顺序错误会抛
InvalidOperationException
若用了自定义仓储模式,别把
IgnoreQueryFilters()
封装进通用 Get 方法里,否则容易误开后门;应单独暴露如
GetAllIncludingDeleted()
这类明确语义的方法 IsDeleted 字段没生效?检查这三处 最常见失效原因不是代码写错,而是模型配置和运行时行为不匹配。 C知道 CSDN推出的一款AI技术问答工具 下载
IsDeleted
属性未映射到数据库列:确认实体类中该属性有对应字段,且未被
[NotMapped]
标记;若用 Fluent API 映射,要确保没漏掉
Property(x => x.IsDeleted)
实体继承体系中父类配置了过滤器,但子类没调用
base.OnModelCreating()
——子类
OnModelCreating
必须显式调用基类方法,否则父类过滤器不生效 使用了
AsSplitQuery()
或多表 JOIN 查询时,EF Core 8+ 才支持将全局过滤器正确应用到所有参与表;旧版本(如 EF Core 6)可能只过滤主表,导致关联数据“漏出”已删除项 软删除与并发更新冲突怎么处理 当业务同时涉及「逻辑删除」和「状态变更」(如用户禁用 + 删除),直接执行
Update
可能意外激活已删除记录。 推荐做法是:所有修改操作都显式检查
IsDeleted == false
,例如:
var user = await context.Users.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);
而不是先查再判断——避免中间状态被并发修改。 不要依赖
Attach
+
Entry.State = Modified
更新软删除实体,这会绕过查询过滤,可能更新到已删除行 若必须批量恢复(如“还原选中用户”),用原始 SQL 或
ExecuteUpdateAsync
(EF Core 7+)并显式加
WHERE IsDeleted = 1
条件,避免全表扫描 数据库层面建议给
IsDeleted
列加约束(如
CHECK (IsDeleted IN (0,1))
),防止数据异常污染过滤逻辑 全局过滤器看着简单,但一旦嵌套在继承、多上下文、读写分离或 CQRS 架构里,
HasQueryFilter
的作用域和组合行为就很容易出人意料。尤其要注意它不参与 EF Core 的变更跟踪判定——被过滤掉的实体不会进入
ChangeTracker
,这点常被忽略。

相关文章