如何在Entity Framework中针对该场景缓存数据表,仅发起一次数据库调用
问题描述
现有如下代码:
var fdPositions = dbContext.FdPositions.Where(s => s.LastUpdated > DateTime.UtcNow.AddDays(-1)); foreach (JProperty market in markets) { // bunch of logic that is irrelevant here var fdPosition = fdPositions.Where(s => s.Id == key).FirstOrDefault(); if (fdPosition is not null) { fdPosition.OddsDecimal = oddsDecimal; fdPosition.LastUpdated = DateTime.UtcNow; } else { // bunch of logic that is irrelevant here } } await dbContext.SaveChangesAsync();
遍历约10000个markets时,每次循环都会执行var fdPosition = fdPositions.Where(s => s.Id == key).FirstOrDefault();发起一次数据库调用,总计约10000次请求。
需求是仅在var fdPositions = dbContext.FdPositions.Where(s => s.LastUpdated > DateTime.UtcNow.AddDays(-1));这一行发起一次数据库调用,将数据加载到本地缓存,后续循环直接在本地查询匹配对象,同时确保修改后的对象能通过await dbContext.SaveChangesAsync();正确同步至数据库。
解决方案
核心是将EF的IQueryable转为本地字典集合,实现单次数据库查询+高效本地匹配,具体修改如下:
// 一次性加载符合条件的数据到内存,并转为以Id为键的字典(仅发起一次数据库请求) var fdPositionsDict = dbContext.FdPositions .Where(s => s.LastUpdated > DateTime.UtcNow.AddDays(-1)) .ToDictionary(s => s.Id); foreach (JProperty market in markets) { // bunch of logic that is irrelevant here // 直接从本地字典查询,无额外数据库请求 if (fdPositionsDict.TryGetValue(key, out var fdPosition)) { fdPosition.OddsDecimal = oddsDecimal; fdPosition.LastUpdated = DateTime.UtcNow; } else { // bunch of logic that is irrelevant here } } await dbContext.SaveChangesAsync();
关键说明
ToDictionary()方法会立即执行IQueryable的查询,将数据加载到内存中,全程仅发起一次数据库请求。- 字典的
TryGetValue方法查询效率为O(1),比在普通List中遍历查找更高效,适配10000次循环的场景。 - 从字典中取出的
fdPosition仍然被EF的DbContext追踪,修改属性后调用SaveChangesAsync()会自动将变更同步到数据库。
内容的提问来源于stack exchange,提问作者user3533755
相关产品推荐
相关产品推荐

