【发布时间】:2019-08-05 07:10:17
【问题描述】:
在一个带有 EF 核心的 Asp.Net Core 2.2 项目中(最新的一切,今天运行了所有 NuGet 更新)我有这个操作:
return Ok(_db.GlobalRoles
.Include(gr => gr.GlobalRoleFeatures)
.ThenInclude(grf => grf.Feature)
.Include(gr => gr.GlobalRoleCompanyGroupRoles)
.ThenInclude(grcgr => grcgr.CompanyGroupRole)
.ThenInclude(cgr => cgr.CompanyGroupRoleFeatures)
.ThenInclude(cgrf => cgrf.Feature)
.ToList());
在大多数情况下,细节并不重要,只要说它是我想要预先加载的实体树就足够了。当我分析数据库时,这最终会导致 4 个查询。起初我发现这出乎意料,但不以为然,因为这可能只是 EF 如何优化获取这些结果。没什么大不了。并且得到的数据是正确的。
但是当我把它包裹在IMemoryCache:
return Ok(_cache.GetOrCreate(nameof(GlobalRole), entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(_appSettings.DataCacherExpiryMinutes);
return _db.GlobalRoles
.Include(gr => gr.GlobalRoleFeatures)
.ThenInclude(grf => grf.Feature)
.Include(gr => gr.GlobalRoleCompanyGroupRoles)
.ThenInclude(grcgr => grcgr.CompanyGroupRole)
.ThenInclude(cgr => cgr.CompanyGroupRoleFeatures)
.ThenInclude(cgrf => cgrf.Feature)
.ToList();
}));
虽然此数据的第一次提取按预期工作,但随后从缓存中提取会导致异常:
Newtonsoft.Json.JsonSerializationException:从“Castle.Proxies.GlobalRoleProxy”上的“GlobalRoleCompanyGroupRoles”获取值时出错。 ---> System.InvalidOperationException:为警告“Microsoft.EntityFrameworkCore.Infrastructure.LazyLoadOnDisposedContextWarning”生成错误:在关联的 DbContext 被处置后,尝试在实体类型“GlobalRoleProxy”上延迟加载导航属性“GlobalRoleCompanyGroupRoles”。通过将事件 ID 'CoreEventId.LazyLoadOnDisposedContextWarning' 传递给 'DbContext.OnConfiguring' 或 'AddDbContext' 中的 'ConfigureWarnings' 方法,可以抑制或记录此异常。
似乎在序列化对象时,预先加载的包含实体列表不存在。 (或者也许它们是,但它仍在尝试再次加载它们?或者以某种方式查询上下文?)当然,上下文实例早就被释放了,应该缓存完全物化的列表。
当我调试时,顶级列表确实是从缓存中返回的。但检查后,其中任何对象的GlobalRoleFeatures 和GlobalRoleCompanyGroupRoles 属性都会导致上述相同的异常。
注意:在查询中使用 .ToListAsync() 和 async 一直到 .GetOrCreateAsync() 和控制器操作的行为相同。
我是否忽略了什么?有没有办法将不再依赖于 DB 上下文的完全物化列表放入内存缓存中?
【问题讨论】:
标签: asp.net-core-webapi asp.net-core-2.2 ef-core-2.2