如何为不同EF对象复用Linq的Where查询条件以避免代码重复?
解决方案
问题根源
报错是因为 EF 针对数据库的IQueryable查询需要传入表达式树(Expression Tree) 来翻译为SQL,自定义方法无法被EF解析为SQL语句,因此抛出无法识别方法的异常。
最优实现方案
我们可以把过滤条件统一抽取为Expression<Func<BatchProcessing, bool>>类型的表达式,数据库查询直接使用该表达式,本地集合查询只需调用表达式的Compile()方法转为委托即可使用。
代码实现
- 抽取公共过滤表达式:
// 可以写在BatchProcessingModel类内部,也可以单独放在工具类中 public static Expression<Func<BatchProcessing, bool>> GetMatchFilter(BatchProcessingModel bpm) { return x => x.FooAttr1 == bpm.FooAttr1 && x.FooAttr2 == bpm.FooAttr2 // 其余条件保持和之前一致 && ...; }
- 改写原有业务代码:
public async Task ExecuteAsync(BatchProcessingModel bpm) { using (_dbFoo = new FooEntities(_fooConnexionString)) { // 统一获取过滤器 var matchFilter = GetMatchFilter(bpm); // 数据库查询直接传表达式,可正常翻译为SQL var bprInBdd = await _dbFoo.BatchProcessing .Where(matchFilter) .ToListAsync(); // 本地集合查询调用Compile()转为Func委托 var bprLocal = _dbFoo.BatchProcessing.Local .Where(matchFilter.Compile()) .ToList(); if (bprLocal.Count == 0 && bprInBdd.Count == 0) { // add new BatchProcessing in BDD } } }
优化可选方案
如果不想每次写Compile(),可以给本地IEnumerable写个扩展方法重载,简化调用:
public static class BatchProcessingExtensions { public static IEnumerable<BatchProcessing> Where(this IEnumerable<BatchProcessing> source, Expression<Func<BatchProcessing, bool>> filter) { return source.Where(filter.Compile()); } }
引入扩展方法后,本地查询的代码可以和数据库查询写法完全一致:
var bprLocal = _dbFoo.BatchProcessing.Local.Where(matchFilter).ToList();
内容的提问来源于stack exchange,提问作者Oudini
相关产品推荐
相关产品推荐

