You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:55:31