Blazor Server中Entity Framework Core无法加载数据库最新数据问题
问题原因
Blazor Server中DbContext默认是Scoped生命周期,会和用户的SignalR连接绑定复用。EF Core的**一级缓存(内存跟踪缓存)**会保留之前查询到的实体数据,所以更新数据库后,直接查询会从缓存取旧数据,只有页面刷新(重建上下文)才会拿到新数据。你之前用ReloadAsync报错是因为这个方法只能针对单个实体,不能传入List<T>,EF无法识别List作为实体类型。
解决方法
方法1:查询时禁用跟踪(推荐)
在查询方法中加入AsNoTracking(),让EF不缓存查询结果,每次直接从数据库获取最新数据:
async Task<string> ISoftwareSectionUserService.GetUserSoftwareSections(int userId) { try { var softwareSectionsList = await _sqliteContext.UserSoftwareSections .AsNoTracking() // 禁用实体跟踪,跳过一级缓存 .Include(x => x.SoftwareSectionRefNavigation) .Where(x => x.UserRef == userId) .ToListAsync(); var settings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; return JsonConvert.SerializeObject(new ServiceResultModel<List<UserSoftwareSection>> { Succeed = true, Data = softwareSectionsList }, settings); } catch (Exception ex) { return JsonConvert.SerializeObject(new ServiceResultModel<string> { Succeed = false, Message = (ex.Message + " " + ex.InnerException) }); } }
方法2:更新后清空上下文跟踪缓存
在SetSoftwareSectionPermissions方法完成数据更新后,清空上下文的跟踪缓存,让下次查询重新加载数据:
async Task<string> ISoftwareSectionUserService.SetSoftwareSectionPermissions(Dictionary<string, string> softwareSections, int userId) { try { var newUserSoftwareSections = new List<UserSoftwareSection>(); var selectedItemsToDelete = await _sqliteContext.UserSoftwareSections.Where(x => x.UserRef == userId).ToListAsync(); await _sqliteContext.BulkDeleteAsync(selectedItemsToDelete); await _sqliteContext.SaveChangesAsync(); foreach (var item in softwareSections) { var selectedSectionUser = await _sqliteContext.UserSoftwareSections .FirstOrDefaultAsync(x => x.UserRef == userId && x.SoftwareSectionRefNavigation.SectionName == item.Key);//Key is section name var selectedSection = await _sqliteContext.SoftwareSections.FirstOrDefaultAsync(x => x.SectionName == item.Key);//Value is permision string if (selectedSectionUser == null) { var userSoftwareSection = new UserSoftwareSection { UserRef = userId, SectionRef = (int)selectedSection?.SectionId, Permissions = item.Value }; newUserSoftwareSections.Add(userSoftwareSection); } } await _sqliteContext.BulkInsertAsync(newUserSoftwareSections, config => config.BatchSize = 100); await _sqliteContext.SaveChangesAsync(); // 清空上下文跟踪缓存 _sqliteContext.ChangeTracker.Clear(); return JsonConvert.SerializeObject(new ServiceResultModel<string> { Succeed = true }); } catch (Exception ex) { return JsonConvert.SerializeObject(new ServiceResultModel<string> { Succeed = false, Message = (ex.Message + " " + ex.InnerException) }); } }
方法3:确认DbContext生命周期配置
确保你的SqliteContext在Program.cs中注册为Scoped(Blazor Server的正确做法),避免用Singleton导致上下文共享缓存混乱:
builder.Services.AddDbContext<SqliteContext>(options => options.UseSqlite("YourConnectionString"), ServiceLifetime.Scoped);
补充:关于你之前的错误
_sqliteContext.Entry(softwareSectionsList).ReloadAsync()报错的原因是:Entry()方法只能接收单个实体对象,而你传入的是List<UserSoftwareSection>集合。EF Core的模型中只定义了UserSoftwareSection实体,没有List类型,所以会提示找不到该实体类型。如果要重新加载单个实体,应该遍历集合对每个实体调用ReloadAsync(),但这种方式效率低,不如前面的方法实用。
内容的提问来源于stack exchange,提问作者Alex Wright
相关产品推荐
相关产品推荐

