Blazor中调用存储过程第二次时列表数据未正确更新问题
问题解决:Blazor中EF调用存储过程后DateTime列未更新
问题场景
在Blazor应用中使用Entity Framework Core通过存储过程填充数据网格,页面初始化和日期ValueChange事件触发时调用存储过程。首次调用正常,但更改日期后,存储过程接收新日期参数并返回结果,其中重新计算的dataScadenta(DateTime类型)列数据未更新,列表虽有变化但数据不正确。相同存储过程在.NET Framework的EF应用中运行正常。
现有代码
获取数据函数
public async Task<List<TabelRaportari>> GetData(DateTime dataRef) { string dataUWU = dataRef.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); List<TabelRaportari>? data = null; _dbContext.TabelRaportaris.Local.Clear(); data = await _dbContext.TabelRaportaris .FromSqlInterpolated($"EXEC RASF {dataUWU}, null") .ToListAsync(); return data; }
模型类
public class TabelRaportari { public int id { get; set; } public string? name { get; set; } public string? limit { get; set; } public string? obs { get; set; } public DateTime? dataScadenta { get; set; } }
问题原因
EF Core的**变更跟踪器(Change Tracker)**会缓存已加载的实体。当存储过程返回与之前相同id的实体时,EF Core会优先使用缓存中已存在的实体数据,而非存储过程返回的新数据,导致dataScadenta这类被跟踪的字段无法更新。而.NET Framework中的EF6默认行为或缓存机制与EF Core不同,因此未出现此问题。
_dbContext.TabelRaportaris.Local.Clear()仅清除本地缓存集合,并未移除变更跟踪器中已跟踪的实体,所以无法解决根本问题。
解决方案
方案1:查询时禁用跟踪(推荐)
在查询方法中添加.AsNoTracking(),让EF Core不跟踪从存储过程返回的实体,每次都获取全新的数据:
public async Task<List<TabelRaportari>> GetData(DateTime dataRef) { string dataUWU = dataRef.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); return await _dbContext.TabelRaportaris .FromSqlInterpolated($"EXEC RASF {dataUWU}, null") .AsNoTracking() // 禁用跟踪,跳过缓存 .ToListAsync(); }
这种方式简单高效,适合数据网格这类只读场景。
方案2:清空变更跟踪器中的所有实体
如果需要保留实体跟踪,可以在查询前清空变更跟踪器中所有已跟踪的实体:
public async Task<List<TabelRaportari>> GetData(DateTime dataRef) { string dataUWU = dataRef.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); // 解除所有实体的跟踪状态 foreach (var entity in _dbContext.ChangeTracker.Entries()) { entity.State = EntityState.Detached; } return await _dbContext.TabelRaportaris .FromSqlInterpolated($"EXEC RASF {dataUWU}, null") .ToListAsync(); }
方案3:使用独立的DbContext实例
每次调用GetData时创建新的DbContext实例,避免上下文复用导致的缓存问题:
// 注入DbContext工厂 private readonly IDbContextFactory<YourDbContext> _dbContextFactory; public YourService(IDbContextFactory<YourDbContext> dbContextFactory) { _dbContextFactory = dbContextFactory; } public async Task<List<TabelRaportari>> GetData(DateTime dataRef) { string dataUWU = dataRef.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); using var dbContext = _dbContextFactory.CreateDbContext(); return await dbContext.TabelRaportaris .FromSqlInterpolated($"EXEC RASF {dataUWU}, null") .ToListAsync(); }
此方法适合需要隔离上下文的场景,但会增加上下文创建开销。
额外检查点
- 确认存储过程返回的
dataScadenta列名称与模型属性完全匹配(注意数据库是否区分大小写)。 - 直接在数据库工具(如SSMS)中执行存储过程,验证传入新日期后是否返回正确的
dataScadenta值。
内容的提问来源于stack exchange,提问作者oakscout
相关产品推荐
相关产品推荐

