使用LINQ和Entity Framework Core分页时丢失记录的解决方法
修复分批处理数据的分页问题
你的问题根源在于初始获取的未处理数据总数是静态值:后续每批数据处理并更新IsProcessed后,数据库中未处理的数据量已减少,但循环依然按照初始的总数(167)计算跳过的行数(processedBatch累加50)。当processedBatch达到150时,执行Skip(150)查询未处理数据,此时数据库仅剩17条未处理数据,Skip(150)会跳过所有剩余数据,导致无法获取最后一批。
解决方案
不需要提前获取总未处理数,改为每次循环直接查询当前未处理的前50条数据,直到返回的批次为空,即可覆盖所有数据。这种方式更高效,也能避免静态总数带来的偏差。
修复后的代码
var getUnProcessedDataQuery = context.ProcessData .Where(p => p.ProcessId == 100 && !p.IsProcessed) .OrderBy(p => p.ProcessDataId); while (true) { // 每次获取当前未处理的前50条数据 var processDataChunk = getUnProcessedDataQuery.Take(50).ToList(); // 无数据则退出循环 if (!processDataChunk.Any()) break; foreach (var data in processDataChunk) { try { // 执行数据处理逻辑 data.IsProcessed = true; } catch (Exception ex) { data.IsProcessed = false; // 可添加异常日志记录逻辑 } } // 批量更新当前批次的处理状态 await BulkUpdateProcessData(processDataChunk); }
备选方案(保留分页扩展)
如果仍想使用现有的ToPagedList扩展,需调整循环逻辑,每次重新获取当前未处理数据的数量,并累加实际处理的批次大小:
var getUnProcessedDataQuery = context.ProcessData .Where(p => p.ProcessId == 100 && !p.IsProcessed) .OrderBy(p => p.ProcessDataId); int processedBatch = 0; while (true) { int currentUnProcessedCount = getUnProcessedDataQuery.Count(); if (currentUnProcessedCount == 0) break; var processDataChunk = getUnProcessedDataQuery.ToPagedList(processedBatch, 50, currentUnProcessedCount); if (!processDataChunk.Any()) break; foreach (var data in processDataChunk) { try { // 执行数据处理逻辑 data.IsProcessed = true; } catch (Exception ex) { data.IsProcessed = false; } } await BulkUpdateProcessData(processDataChunk); // 累加实际处理的数量,而非固定50 processedBatch += processDataChunk.Count; }
注意事项
- 优先选择第一种方案,避免每次循环查询总计数的额外开销,直接取Top 50直到为空即可。
- 确保
BulkUpdateProcessData方法能正确将实体的IsProcessed状态同步到数据库。
内容的提问来源于stack exchange,提问作者I Love Stackoverflow
相关产品推荐
相关产品推荐

