如何遍历列表构建LINQ查询?解决查询无法翻译报错
问题描述
我有一段可正常运行的LINQ查询:
posts.Where(post => post.Fields .Where(x => x.RegionId == "RecipeArticleDetails" && (x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime") ) .GroupBy(x => x.PostId) .Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) }) .Where(x => x.Value > 10 && x.Value < 40) .Any() ) List<string> suppliedTimes = new List<string>(){ "10-60","0-10" };
我想把其中的Where(x => x.Value > 10 && x.Value < 40)替换成从suppliedTimes列表读取的时间范围筛选条件,尝试了以下代码却报错:
posts.Where(post => suppliedTimes.Select(x => new {low = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[0]), high = Convert.ToInt32(x.Split("-",StringSplitOptions.RemoveEmptyEntries)[1]) }) .Any( a => post.Fields .Where(x => x.RegionId == "RecipeArticleDetails" && (x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime") ) .GroupBy(x => x.PostId) .Select(x => new { ID = x.Key, Value = x.Sum(y => Convert.ToInt32(y.Value)) }) .Where(x => x.Value > a.low && x.Value < a.high) .Any() ) )
报错信息:
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
报错原因
- EF Core无法将
suppliedTimes.Select(...)里的客户端操作(字符串Split、Convert.ToInt32类型转换)翻译成SQL语句,这类内存中的逻辑没有对应的数据库执行逻辑。 - 嵌套的
Any结合动态生成的范围对象,导致查询结构过于复杂,ORM无法解析为合法的数据库查询语句。
解决方法
核心思路是提前在客户端解析时间范围,避免在EF Core查询中执行无法翻译的操作,再将多范围筛选转化为数据库可识别的逻辑。
步骤1:预解析时间范围
先把suppliedTimes的字符串格式转换成整数范围列表,放在客户端内存中:
var timeRanges = suppliedTimes .Select(s => { var parts = s.Split("-", StringSplitOptions.RemoveEmptyEntries); return new { Low = int.Parse(parts[0]), High = int.Parse(parts[1]) }; }) .ToList();
步骤2:重构LINQ查询
方法一:简化嵌套Any逻辑
将多范围筛选直接合并到统计后的时间判断中:
var filteredPosts = posts .Where(post => post.Fields .Where(x => x.RegionId == "RecipeArticleDetails" && (x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime") ) .GroupBy(x => x.PostId) .Select(g => g.Sum(y => Convert.ToInt32(y.Value))) .Any(totalTime => timeRanges.Any(r => totalTime > r.Low && totalTime < r.High) ) );
方法二:构建表达式树生成OR条件(适配复杂场景)
如果方法一仍有翻译问题,可以手动构建表达式树,把多个范围条件合并成OR逻辑,让EF Core能生成对应的SQL:
// 初始化基础条件为false Expression<Func<int, bool>> rangeCondition = t => false; foreach (var range in timeRanges) { var currentRange = range; // 单个范围的条件表达式 Expression<Func<int, bool>> currentCondition = t => t > currentRange.Low && t < currentRange.High; // 合并为OR逻辑 rangeCondition = Expression.Lambda<Func<int, bool>>( Expression.OrElse(rangeCondition.Body, currentCondition.Body), rangeCondition.Parameters ); } // 应用到最终查询 var filteredPosts = posts .Where(post => post.Fields .Where(x => x.RegionId == "RecipeArticleDetails" && (x.FieldId == "RecipePrepTime" || x.FieldId == "RecipeCookTime") ) .GroupBy(x => x.PostId) .Select(g => g.Sum(y => Convert.ToInt32(y.Value))) .Any(rangeCondition) );
内容的提问来源于stack exchange,提问作者atoms
相关产品推荐
相关产品推荐

