封装Entity Framework IQueryable<T>到Action中过滤器不生效问题排查
问题原因
你用Action<IQueryable<T>>作为筛选器类型是核心问题——IQueryable<T>是不可变的,Linq方法(比如Where)不会修改原对象,而是返回一个包含筛选逻辑的新IQueryable<T>实例。你的filter(query)调用只是执行了lambda表达式,但没有把新生成的查询结果赋值回原变量,所以最终执行的还是未过滤的原始查询。
修正方案
把Action<IQueryable<T>>替换成Func<IQueryable<T>, IQueryable<T>>,让筛选器返回修改后的查询对象,再用这个对象执行最终的ToList()。
修改后的基础仓储代码
namespace Api.Domain.Repository.Base { public abstract class Repository<T> : IRepository<T> where T : BaseTable { private readonly DataContext context; private readonly DbSet<T> entity; public Repository(DataContext context) { this.context = context; entity = context.Set<T>(); } protected IList<T> Select(Func<IQueryable<T>, IQueryable<T>> filter) { if (filter == null) throw new ArgumentNullException(nameof(filter)); var query = entity.AsQueryable<T>(); // 接收筛选器返回的新查询对象 query = filter(query); return query.ToList(); } } }
修改后的特定仓储调用
public IList<Address> GetMinMax(int min, int max) { return Select(q => q .Where(a => a.Id >= min && a.Id <= max)); }
这段调用代码的写法不用变,因为lambda现在会返回处理后的IQueryable<T>,刚好匹配Func的返回值要求。
补充说明
这种封装仓储模式的思路是可行的,用Func替代Action就能解决问题。需要记住Linq to Entities的核心特性:所有查询操作都是生成新的查询表达式树,不会修改原对象,所以必须通过返回值传递修改后的查询逻辑。
内容的提问来源于stack exchange,提问作者Ayrton Albuquerque
相关产品推荐
相关产品推荐

