2026-10-25 10:52:36
在 C# 中使用 EF Core 的全局查询过滤器,可通过 HasQueryFilter 方法在 OnModelCreating 中配置 LINQ 条件,自动应用于实体的所有查询,常用于软删除和多租户场景。
核心配置步骤在 DbContext 中重写 OnModelCreating 方法使用 ModelBuilder 的 Entity<T>.HasQueryFilter 方法为实体设置过滤条件。
示例:实现软删除以下代码为 Blog 和 Post 实体配置了 IsDeleted 过滤条件,所有查询自动排除已删除数据:
public class BloggingContext : DbContext{ public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasQueryFilter(b => !b.IsDeleted); modelBuilder.Entity<Post>() .HasQueryFilter(p => !p.IsDeleted); }}public class Blog{ public int Id { get; set; } public string Name { get; set; } public bool IsDeleted { get; set; }}public class Post{ public int Id { get; set; } public string Title { get; set; } public bool IsDeleted { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; }}效果:所有对 Blog 和 Post 的查询(如 context.Blogs.ToList())会自动添加 !IsDeleted 条件,无需手动编写。
若需查询已软删除的数据,可使用 IgnoreQueryFilters() 方法绕过过滤器:
var deletedBlogs = context.Blogs .IgnoreQueryFilters() .Where(b => b.IsDeleted) .ToList();高级用法:多租户支持通过依赖注入传递租户 ID,实现每个租户只能访问自己的数据:
public class BloggingContext : DbContext{ private readonly string _tenantId; public BloggingContext(string tenantId) { _tenantId = tenantId; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasQueryFilter(b => b.TenantId == _tenantId); }}性能影响
复杂过滤表达式可能导致查询性能下降,建议为过滤字段(如 IsDeleted、TenantId)添加数据库索引。
关联数据过滤
使用 Include 加载导航属性时,过滤器会应用于关联实体。若关联实体被过滤掉,可能导致数据缺失。
静态上下文与单例模式
避免在静态上下文或单例模式下使用依赖注入的过滤器参数(如租户 ID),否则可能导致状态污染。
数据库迁移
过滤器仅在应用层生效,数据库层面不会强制约束,迁移时需手动处理数据一致性。
合理使用全局查询过滤器可显著减少重复代码,提升开发效率,但需注意性能优化和边界条件处理。