В большинстве случаев, когда вы сталкиваетесь с проблемами производительности с MVC и EF, это происходит из-за возврата сущностей в представления и утомленной отложенной загрузкой. Причина этого заключается в том, что когда ASP.Net предписывается отправить объект в браузер, он должен сериализовать его. Процесс сериализации перебирает объект, который касается прокси-серверов с отложенной загрузкой, вызывая загрузку этих связанных объектов по одному.
Вы можете обнаружить это, запустив профилировщик для вашей базы данных, установить точку останова до конца действия, а затем посмотреть, какие запросы выполняются при возврате вызова действия. Ленивая загрузка из-за сериализации будет отображаться в виде нескольких отдельных (TOP 1) запросов, выполняемых в быстрой последовательности после завершения действия до отображения страницы.
Самое простое предложение избежать этой боли - не возвращать сущности из контроллеров.
IQueryable<Item> vItems = vSearchItems.GetItems(vZoekString);
var viewModels = vItems.OrderBy(x => x.ITEM)
.Select(x => new ItemViewModel
{
ItemId = x.ItemId,
// .. Continue populating view model. If model contains a hierarchy of data, map those to related view models as well.
}).ToPagedList(page, pageSize);
return View(viewModels);
Преимущество такого подхода:
-
.Select()
приведет к запросу, который извлекает только те данные, которые вам действительно нужны для заполнения моделей представлений. (Данные, которые нужны вашему просмотру) Более быстрый запрос, меньше данных по проводам между сервером БД -> Сервер приложений -> Браузер
- Это не приводит к ленивым нагрузкам.
Предостережение этого подхода:
- Необходимо позаботиться о том, чтобы выражение
.Select()
перешло в SQL, поэтому нет .Net или частных функций для таких вещей, как перевод / форматирование данных. Заполните необработанные значения в модели представления, а затем откройте свойства модели представления, чтобы выполнить перевод, который будет сериализовать эти отформатированные данные клиенту. Базовые вещи, такие как FullName = x.FirstName + " " + x.LastName
- это хорошо, но избегайте таких вещей, как OrderDate = DateTime.Parse(x.DateAsISO)
, если в БД хранятся даты в виде строк.
Вы можете использовать сопоставители, такие как Automapper, чтобы помочь в сопоставлении между Entity и ViewModel. При условии, что картографический инструмент проверяет / пересекает место назначения для заполнения, а не источник, вы должны быть хорошими. Automapper поддерживает интеграцию в IQueryable
, поэтому было бы целесообразно изучить, если вы хотите использовать картограф.