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

Blazor Server下Entity Framework查询返回旧值问题排查

问题判断

你的猜测不正确,该问题和事务隔离级别无关,是由EF Core一级查询缓存和Blazor Server的服务生命周期特性共同导致的。

根因说明

  1. Blazor Server的每个浏览器标签页对应独立的SignalR长连接,也对应一个专属的依赖注入Scope。你通过AddDbContext注册的MyDbContext默认是Scoped生命周期,只要page1的标签页不刷新/关闭,这个Scope里的MyDbContext实例就会一直存活。
  2. EF Core的DbContext默认启用实体跟踪,第一次查询Id=5的MyTable实体时,EF会将该实体缓存到上下文的一级缓存中。后续同一个DbContext实例再查询相同主键的实体时,会直接返回缓存的旧实体,不会向数据库发起查询,因此感知不到page2的更新。

额外注意

你原有代码中查询条件写的是i => i.Id=5,属于赋值操作,需要修改为相等判断i => i.Id == 5,否则会触发逻辑错误。另外MyService类没有显式实现IMyService接口,注册时会抛出服务实现不匹配的异常,需要补充接口继承。

解决方案

推荐按优先级选择以下方案:

方案1(最优):MyService注入DbContext工厂,每次查询创建独立上下文

修改MyService的实现,每次查询都新建DbContext,用完即释放,从根源避免缓存问题:

public class MyService : IMyService
{
    private readonly IDbContextFactory<MyDbContext> _dbFactory;

    public MyService(IDbContextFactory<MyDbContext> dbFactory)
    {
        _dbFactory = dbFactory;
    }

    public string getInformationFromTable()
    {
         using var db = _dbFactory.CreateDbContext();
         // 空值避免空引用异常
         return db.MyTable.FirstOrDefault(i => i.Id == 5)?.MyField ?? string.Empty;
    } 
}

方案2:查询时禁用实体跟踪

如果不想修改注入逻辑,可以在查询时加AsNoTracking(),强制每次查询都从数据库拉最新数据:

public string getInformationFromTable()
{
     return _db.MyTable.AsNoTracking().FirstOrDefault(i => i.Id == 5)?.MyField ?? string.Empty;
}

方案3:手动刷新缓存实体

如果必须保留跟踪逻辑,可以在查询后手动重载实体:

public string getInformationFromTable()
{
     var entity = _db.MyTable.Find(5);
     if (entity != null)
     {
         _db.Entry(entity).Reload();
         return entity.MyField;
     }
     return string.Empty;
}

内容的提问来源于stack exchange,提问作者Bob5421

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 03:45:04