Blazor Server下Entity Framework查询返回旧值问题排查
问题判断
你的猜测不正确,该问题和事务隔离级别无关,是由EF Core一级查询缓存和Blazor Server的服务生命周期特性共同导致的。
根因说明
- Blazor Server的每个浏览器标签页对应独立的SignalR长连接,也对应一个专属的依赖注入Scope。你通过
AddDbContext注册的MyDbContext默认是Scoped生命周期,只要page1的标签页不刷新/关闭,这个Scope里的MyDbContext实例就会一直存活。 - 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
相关产品推荐
相关产品推荐

