ASP.NET Core MVC内存缓存IQueryable数据遇ObjectDisposedException求助
ASP.NET Core MVC内存缓存报错ObjectDisposedException的解决
报错原因
你缓存了IQueryable<v_ListView>对象,但IQueryable是延迟执行的查询表达式,它并没有实际从数据库获取数据,只是保留了对DbContext的引用。ASP.NET Core中DbContext默认是Scoped生命周期,请求结束后会被自动释放。当后续请求使用缓存的IQueryable时,DbContext已经被销毁,就会抛出ObjectDisposedException。
另外你原代码还有一个隐藏问题:所有Where过滤都没有生效——因为IQueryable是不可变的,Where方法会返回一个新的查询实例,你必须把结果重新赋值给变量,否则原来的CompanyList不会应用任何过滤逻辑。
修复步骤
1. 缓存实际数据集合而非IQueryable
把缓存对象从IQueryable改成List<v_ListView>,这样在缓存时就执行数据库查询,得到内存中的数据集合,不再依赖DbContext。
2. 修正过滤逻辑的赋值问题
所有Where的结果必须重新赋值给变量,确保过滤逻辑生效。
修复后的完整代码
public async Task<(List<v_ListView>, int TotalCount)> GetList(ListDatatableParam param) { string cacheKey = "ListViewKey"; List<v_ListView> cachedList; // 尝试获取全量数据缓存 if (!_memoryCache.TryGetValue(cacheKey, out cachedList)) { // 执行数据库查询,获取全量数据并存入缓存 cachedList = await _Context.v_ListView.ToListAsync(); _memoryCache.Set(cacheKey, cachedList, new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromSeconds(60))); } // 基于缓存的内存集合进行过滤 var filteredList = cachedList.AsQueryable() .Where(p => string.IsNullOrEmpty(SearchTerm) || (!string.IsNullOrEmpty(p.name) && SearchTerm.Length <= p.name.Length && p.name.ToLower().Contains(SearchTerm)) || (!string.IsNullOrEmpty(p.CompanyNumber.ToString()) && p.CompanyNumber.ToString().ToLower().Contains(SearchTerm)) ); if (!filterStatus.Contains("All") && filterStatus[0] != null) { filteredList = filteredList.Where(x => filterStatus.Contains(x.Status)); } if (filterRegion[0] != null) { if (filterRegion.Contains("No Region")) { filteredList = filteredList.Where(x => x.Region == null || x.Region.Equals(string.Empty)); } else { filteredList = filteredList.Where(x => filterRegion.Contains(x.Region)); } } int totalCount = filteredList.Count(); var paginatedList = filteredList.Skip(param.iDisplayStart).Take(param.iDisplayLength).ToList(); return (paginatedList, totalCount); }
进阶优化(针对大数据量场景)
如果v_ListView数据量很大,全量缓存会占用过多内存,建议根据查询参数生成唯一缓存Key,缓存过滤后的结果:
// 组合所有查询参数生成唯一缓存Key,避免不同查询共用缓存 string cacheKey = $"ListView_{SearchTerm}_{string.Join("|", filterStatus)}_{string.Join("|", filterRegion)}_{param.iDisplayStart}_{param.iDisplayLength}";
内容的提问来源于stack exchange,提问作者Milacay
相关产品推荐
相关产品推荐

