EF Core 6预览版LINQ查询无法翻译强制使用.AsEnumerable()问题
问题根因
EF Core 6对LINQ到SQL的翻译规则做了收紧,废弃了旧版本中部分隐式跨查询边界的翻译支持,你现有写法中提前调用AsEnumerable()会将查询转为客户端内存集合,后续针对内存集合的Contains操作无法被EF Core 6翻译为SQL语句,因此强制要求显式客户端评估。
优化方案
方案1:全量使用IQueryable链式查询(最优,性能最高)
不要提前调用AsEnumerable(),保留所有查询为IQueryable类型,EF Core 6可自动将整段逻辑翻译为SQL关联/子查询,全程在数据库端执行,无需提前拉取全量数据到内存:
// 保留查询为IQueryable,不触发客户端执行 var data1Query = _dbContext.Dataset1 .Where(f => f.PostedDate >= DateSince && f.PostedDate <= DateUntil); var ordersQuery = _dbContext.Orders .Where(o => data1Query.Select(f => f.OrderID).Contains(o.OrderID)); var itemsQuery = _dbContext.Items .Where(i => ordersQuery.Select(o => o.OrderID).Contains(i.OrderId)); // 直接关联查询订单和对应商品,一次数据库请求完成所有数据拉取 var orderWithItems = ordersQuery .GroupJoin( itemsQuery, o => o.OrderID, i => i.OrderId, (order, items) => new { Order = order, Items = items } ) .ToList(); // 执行业务逻辑 foreach(var orderGroup in orderWithItems) { var order = orderGroup.Order; var itms = orderGroup.Items; // ... 原有逻辑 }
方案2:用导航属性查询(如果已配置实体外键关联)
如果你的Dataset1、Orders、Items实体之间已配置了一对多导航属性,写法可进一步简化:
var result = _dbContext.Dataset1 .Where(f => f.PostedDate >= DateSince && f.PostedDate <= DateUntil) .Include(f => f.Orders) .ThenInclude(o => o.Items) .ToList();
方案3:拆分查询拉取ID集合
如果确实需要拆分查询步骤,可以先拉取对应ID的值类型集合,EF Core 6支持直接翻译本地值类型集合的Contains操作为SQL的IN语句:
// 先拉取符合条件的订单ID列表 var orderIds = _dbContext.Dataset1 .Where(f => f.PostedDate >= DateSince && f.PostedDate <= DateUntil) .Select(f => f.OrderID) .ToList(); // 本地List的Contains可被EF Core 6正常翻译 var orders = _dbContext.Orders .Where(o => orderIds.Contains(o.OrderID)) .ToList(); var itemOrderIds = orders.Select(o => o.OrderID).ToList(); var items = _dbContext.Items .Where(i => itemOrderIds.Contains(i.OrderId)) .ToList();
无需调整EF Core全局配置,按以上方案调整查询写法即可兼容EF Core 6的翻译规则,同时避免全量数据拉取带来的内存占用过高问题。
内容的提问来源于stack exchange,提问作者Roberto
相关产品推荐
相关产品推荐

