Использование свойств навигации Entity Framework без создания большого количества запросов (избегая N + 1) - PullRequest
2 голосов
/ 14 мая 2011

Я использую Entity Framework Profiler для проверки доступа к данным в проекте MVC и перебрал несколько страниц, где я делаю гораздо больше запросов к базе данных из-за проблем N + 1.

Вот простой пример, показывающий мою проблему:

var club = this.ActiveClub; // ActiveClub uses code similar to context.Clubs.First() 
var members = club.Members.ToList();
return View("MembersWithAddress", members);

Представление проходит по элементам Member и затем следует свойству navigion для каждого участника, чтобы также показать их адрес.Каждый из запросов адреса приводит к дополнительному запросу в БД.

Один из способов решить эту проблему - использовать Включить, чтобы убедиться, что дополнительные таблицы, которые мне нужны, запрашиваются заранее.Тем не менее, я, кажется, могу сделать это только с помощью ObjectSet of Clubs, прикрепленной непосредственно к контексту.В этом случае свойство ActiveClub совместно используется многими контроллерами, и я не всегда хочу запрашивать член и таблицу адресов заранее.

Я бы хотел использовать что-то вроде:

var members = club.Members.Include("Address").ToList();

Но Members - это EntityCollection, и в нем нет метода Include.

Есть ли способ принудительно загрузить член EntityCollection и попросить EF также загрузить их адреса??

Или, используя таким образом свойства навигации EntityCollection для сущности, просто очень плохая идея;и вы должны знать, что вы загружаете, когда получаете его из контекста?

1 Ответ

5 голосов
/ 14 мая 2011

Если ваши объекты наследуют от EntityObject, попробуйте использовать это:

var members = club.Members.CreateSourceQuery()
                          .Include("Address")
                          .ToList();

Если вы используете POCO с прокси-серверами с отложенной загрузкой, попробуйте использовать это:

var members = ((EntityCollection<Club>)club.Members).CreateSourceQuery()
                                                    .Include("Address")
                                                    .ToList();

Очевидно, вторая версияне очень хорошо, потому что POCO используются для удаления зависимости от EF, но теперь вам нужно преобразовать коллекцию в класс EF.Другая проблема заключается в том, что запрос будет выполнен дважды.Ленивая загрузка вызовет Members один раз для доступа к свойству, а затем будет выполнен второй запрос при вызове ToList.Эту проблему можно решить, отключив отложенную загрузку перед выполнением запроса.

Когда вы говорите, что ActiveClub является общим, я считаю, что это означает что-то вроде свойства в базовом контроллере, используемого в производнойконтроллеры.В таком случае вы все равно можете использовать другой код в другом контроллере для заполнения свойства.

...