В проекте Asp.Net Core 2.2 с ядром EF (последние все, все обновления 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: Ошибка при получении значения из «GlobalRoleCompanyGroupRoles» для «Castle.Proxies.GlobalRoleProxy». ---> System. Это исключение можно подавить или зарегистрировать, передав идентификатор события «CoreEventId.LazyLoadOnDisposedContextWarning» методу «ConfigureWarnings» в «DbContext.OnConfiguring» или «AddDbContext».
Похоже, что при сериализации объекта нет загруженных списков содержащихся объектов. (Или, возможно, они есть, но он все еще пытается загрузить их снова? Или каким-то образом запросить контекст?) Естественно, экземпляр контекста давно удален, должен быть кэширован только полностью материализованный список.
Когда я отлаживаю, список верхнего уровня действительно возвращается из кеша. Но после проверки свойства GlobalRoleFeatures
и GlobalRoleCompanyGroupRoles
любого находящегося в нем объекта приводят к тому же вышеупомянутому исключению.
Примечание: То же поведение с использованием .ToListAsync()
в запросе и async
вплоть до .GetOrCreateAsync()
и действия контроллера.
Я что-то пропускаю? Есть ли способ получить полностью материализованный список, больше не зависящий от контекста БД, в кэш-память?