使用Repository时如何为Include关联实体忽略软删除查询过滤器
问题原因
EF Core 5中IgnoreQueryFilters()默认作用于调用时查询链中已包含的所有实体,你现有代码的执行顺序错误,先给基础数据集加了过滤器忽略配置,再执行关联加载,导致新增的Include关联实体没有被覆盖到忽略规则。
修复现有代码
调整Repository方法的执行顺序,先完成所有Include关联加载,再统一处理过滤器配置,即可让主实体和所有关联实体同时忽略软删除过滤器:
public ICollection<TEntity> FindAll(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null, bool hideDeleted = true) { using var db = new TEGVContext(); IQueryable<TEntity> query = db.Set<TEntity>(); // 第一步:拼接所有关联加载逻辑 if (include != null) { query = include(query); } // 第二步:统一处理全局过滤器 if (!hideDeleted) { query = query.IgnoreQueryFilters(); } // 第三步:应用自定义过滤条件 return filter == null ? query.ToList() : query.Where(filter).ToList(); }
注意你调用的FindById方法也要同步调整逻辑,和上述执行顺序保持一致。
指定单个Include关联实体忽略过滤器的实现
如果你不需要全量忽略所有实体的过滤器,只想让指定关联实体忽略软删除规则,有两种可选方案:
- 方案1(推荐,兼容EF Core 5):修改全局过滤器的动态逻辑
在DbContext中新增全局开关属性,所有软删除实体的过滤器根据该开关判断是否生效,如需单独控制某类实体,可新增对应实体的开关属性:
需要忽略时直接给DbContext的// DbContext新增属性 public bool IgnoreAllSoftDelete { get; set; } = false; // 全局过滤器配置统一调整为 modelBuilder.Entity<EntityName>().HasQueryFilter(p => IgnoreAllSoftDelete || !p.Deleted);IgnoreAllSoftDelete赋值为true即可,不需要调用IgnoreQueryFilters()方法。 - 方案2:升级到EF Core 7及以上版本
高版本EF Core支持直接在Include链式调用中指定忽略当前关联实体的过滤器:
上述写法仅会忽略Entity2的软删除过滤器,其余实体仍会应用过滤规则。var model = _Repo.FindById(id, include: a => a .Include(x => x.Entity2).IgnoreQueryFilters() .ThenInclude(l => l.Entity2_1) .Include(x => x.Entity3).ThenInclude(l => l.Entity3_1), false);
更优实现方案建议
- 避免在Repository中手动实例化DbContext,改为依赖注入的方式注入DbContext实例,保证同一请求内上下文唯一,减少性能开销,也便于事务管理。
- 软删除全局过滤器统一批量配置:定义
ISoftDelete接口包含Deleted属性,所有需要软删除的实体实现该接口,在DbContext的OnModelCreating方法中批量给所有实现了该接口的实体添加查询过滤器,减少重复代码。 - 可根据业务场景决定是否向上层暴露
IQueryable,避免过度封装Repository导致查询灵活性不足。
内容的提问来源于stack exchange,提问作者Samir Mirghani
相关产品推荐
相关产品推荐

