Как оптимизировать объекты, созданные из запроса в Entity Framework (Граф объектов) - PullRequest
1 голос
/ 01 ноября 2011

Я столкнулся с некоторыми проблемами с памятью при использовании EF4.1, проблемы в основном возникают в такой ситуации: представьте, что у меня есть ученики, которые могут посещать один или несколько курсов, и несколько пользователей могут посещать один и тот же курс.Итак, у меня есть что-то вроде:

Student * < - > 1-* Course

Представьте, что у меня в BD 2 студента и 1 курс.Вот так:

Ана посещает курс английского языка Боб посещает курс английского языка

Мой график объектов выглядит примерно так:

Ana  
    \
      English Course
    /
Bob

Это нормально.

Я сохраняю это, и это прекрасно, две строки в таблице учеников и одна в таблице курсов.

Проблема в том, когда я пытаюсь получить эти данные.

Когда я делаю что-то вроде:

 var students = (from s in students
                 select s).Include("Courses");

Это результирующий график:

 Ana -> English Course
 Bob -> English Course

Объект дублирован.Представьте себе ситуацию, когда глубина этого дерева намного больше, и тысячи студентов и тысячи курсов посещают один и тот же курс.

Использование памяти для этого запроса было бы огромным, как решить эту справочную проблему?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2011

Если вы используете AsNoTracking в своих запросах, объекты не загружаются в контекст и не кэшируются там.Но без контекста у вас нет Identity Mapping, что означает: у вас нет уникального отображения между значениями ключевых свойств и идентификаторами ссылок на объекты.В результате EF создаст новый объект для каждого загруженного свойства навигации, поэтому вы получите несколько объектов для одного и того же ключа.Это ускоряет загрузку, поскольку не нужно создавать карту удостоверений и снимок свойств для отслеживания изменений, но она потребляет потенциально больше памяти.

Насколько я знаю, без загрузки данных в контекст невозможночтобы избежать дублирования объектов во время материализации объектов.

Чтобы возможно повысить производительность при загрузке данных без AsNoTracking, вы можете попытаться перейти от активной загрузки коллекции курсов к явной загрузке.Известно, что активная загрузка приводит к огромному умножению данных, передаваемых между базой данных и клиентом , что может оказать очень негативное влияние на производительность.При явной загрузке ваш код будет выглядеть следующим образом:

// no Include and no AsNoTracking here
var students = (from s in context.Students select s).ToList();
foreach (var student in students)
{
    context.Entry(student).Collection(s => s.Courses).Load();
}

Это создает один дополнительный запрос к базе данных на каждый загруженный student для загрузки коллекции Courses.Относительно производительности это звучит безумно, но есть примеры, что это все же может быть намного быстрее, чем один запрос с активной загрузкой (как показано в этом примере: Обнаружение сущностей, имеющих одинаковых дочерних элементов (см. Комментарии к этомуответ: увеличение производительности с 167 секунд до 3,4 секунд после перехода от нетерпеливой к явной загрузке)).

Объекты не должны дублироваться здесь, потому что они материализованы в контекст.

0 голосов
/ 01 ноября 2011

Ваше значение не дублируется, потому что, если бы у вас было только

Ana -> English Course

, вы не смогли бы узнать, что изучает Боб.Если вас интересуют только отдельные курсы, вы можете использовать отдельное ключевое слово, а также группировать по курсам.Таким образом, если вам нужны были только отдельные значения курсов, у вас не было проблем со ссылками, вы просто сгенерировали неправильный запрос.Если вы можете сказать мне, чего именно вы хотите достичь, я могу помочь вам с дополнительной информацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...