EF调用FromSql获取实体后用Linq的Any方法过滤报错如何解决
问题原因
你当前使用的是EF Core 1.x版本(对应dnx4.5.1、VS2015的运行环境),该版本对FromSql返回的IQueryable嵌套在Linq查询中的支持存在缺陷:
- 你代码里的
listAeGrp和_orders都是未实际执行的IQueryable对象,没有加载到内存 - 当你把
listAeGrp.Any(...)写入_orders的Where条件时,EF Core会尝试把整个表达式翻译成SQL语句,但旧版本无法识别FromSql的重载,直接抛出解析错误。
实现需求的替代方案
方案1:提前加载过滤用的AE列表到内存(改动最小,适配当前环境)
listAeGrp是根据用户ID查询的小数据集,你可以先把它从数据库加载到内存,再用内存集合过滤订单查询,不需要EF解析嵌套的FromSql,修改后的代码如下:
[HttpGet] public async Task<IActionResult> GetViewIO() { int uid = (int)HttpContext.Session.GetInt32("userId").Value; if(uid == 2) { uid = 33; } // 加ToListAsync()提前把AE列表加载到内存,变成普通List集合 var listAeGrp = await _context.ListofAE.FromSql($"Execute ListOfAe {uid}").ToListAsync(); // 提前提取所有AE的id,后续过滤性能更高 var aeIdList = listAeGrp.Select(y => y.id).ToList(); var _orders = _context.OrderHeaderView.FromSql(@"OrderHeaderView").OrderByDescending(f => f.id).OrderBy(p => p.platform_id); // 用内存的aeIdList做Contains判断,EF可以把这个翻译成SQL的IN语句,不会报错 var orders = await _orders.Where(x => aeIdList.Contains(x.created_by)).ToListAsync(); return Json(orders); }
方案2:合并存储过程逻辑
如果订单数据量极大,不想在SQL中使用IN条件,可以直接把AE过滤的逻辑写到订单的存储过程里,一次查询直接返回过滤后的订单结果,不需要应用层做两次查询再过滤,性能更高。
补充说明:如果后续你将EF Core升级到2.0及以上版本,对
FromSql的嵌套查询支持会完善很多,但当前版本环境下优先使用方案1即可。
内容的提问来源于stack exchange,提问作者Monsur MonPaulo
相关产品推荐
相关产品推荐

