EF Core 3.1中使用本地序列执行LINQ to SQL查询报错如何解决
异常原因
抛出该异常是因为EF Core 3.1的LINQ转SQL翻译器存在限制:仅支持本地序列的Contains运算符的翻译,示例中用到的Any运算符作用于本地序列时无法被正确翻译成SQL语句。旧版.NET Framework的Entity Framework对这类写法做了特殊兼容,因此可以正常执行。
可行解决方案
方案1:动态拼接表达式树(生产环境推荐)
该方案通过手动构造OR逻辑拼接多个包含判断的表达式,最终可以将过滤逻辑完全翻译成SQL在数据库端执行,性能最优,适配任意数量的搜索字符串。
首先定义通用扩展方法:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; public static class QueryableExtensions { public static IQueryable<T> WhereAnyContains<T>(this IQueryable<T> query, Expression<Func<T, string>> propertySelector, IEnumerable<string> searchStrings) { if (!searchStrings?.Any() ?? true) return query; var parameter = propertySelector.Parameters.First(); Expression combinedCondition = null; var propertyAccess = propertySelector.Body; var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); foreach (var searchStr in searchStrings) { var searchStrConstant = Expression.Constant(searchStr, typeof(string)); var containsExpression = Expression.Call(propertyAccess, containsMethod, searchStrConstant); combinedCondition = combinedCondition == null ? containsExpression : Expression.OrElse(combinedCondition, containsExpression); } var lambda = Expression.Lambda<Func<T, bool>>(combinedCondition, parameter); return query.Where(lambda); } }
调用方式如下:
var projectSearchStrings = new List<string>() { "Test", "Fake" }; var projects = Projects.WhereAnyContains(p => p.Name, projectSearchStrings).ToList();
方案2:客户端内存过滤(仅适合小数据量场景)
如果项目表数据量极小,可以先将全表数据加载到内存再执行过滤,写法最简单但性能损耗极高,数据量超过千级就不建议使用:
var projectSearchStrings = new List<string>() { "Test", "Fake" }; var projects = Projects.AsEnumerable() .Where(p => projectSearchStrings.Any(x => p.Name.Contains(x))) .ToList();
方案3:升级EF Core版本
如果允许调整依赖版本,EF Core 5.0及以上版本已经原生支持这类本地序列Any+Contains的查询翻译,原有代码无需任何修改即可正常运行。
内容的提问来源于stack exchange,提问作者Manuel Hess
相关产品推荐
相关产品推荐

