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

Я использовал шаблон проектирования, который после использования Entity Framework Profiler кажется довольно глупым.

Я расширил классы сущностей, добавив в них свойства, представляющие собой отфильтрованные представления коллекции, связанной с этой сущностью. Как это:

public IEnumerable<Member> ActiveMembers
{
    get
    {
        return Members.Where(t => t.LeftDate == null);
    }
}

Поскольку я в основном заинтересован в членах, которые не покинули клуб, это свойство было очень полезным и, казалось, имело смысл.

Однако после запуска EF Profiler я теперь знаю, что это часто приводит к проблемам N + 1. Если я перебираю членов, а также хочу показать их адрес, то каждый запрос адреса приводит к дополнительному запросу БД.

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

return Members.CreateSourceQuery().Include("Address")
              .Where(t => t.LeftClubDate == null);

В этом случае это избавит от проблемы N + 1, но мне не всегда нужна информация об адресе, и я мог бы захотеть следовать другому свойству навигации от Member.

В идеале я хочу иметь возможность сохранять гибкость моих отфильтрованных свойств, таких как ActiveMembers, и впоследствии иметь возможность решать, какие свойства включить в запрос. Как это:

var membersToDisplay = ActiveMembers.Include("Address").ToList();

Возможно ли это, или мне нужно изменить мою идею отфильтрованных свойств?

1 Ответ

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

Нет, невозможно набрать Include на IEnumerable.Include является функцией ObjectQuery / DbQuery.Можно вызвать Include на IQueryable (с EFv4.1 или пользовательским расширением), но он по-прежнему внутренне приводит приведенный запрос к ObjectQuery или DbQuery и выдает исключение, если приведение не может быть выполнено.Вы должны перепроектировать свое приложение.

Мне не всегда нужна информация об адресе, и я мог бы хотеть следовать другому свойству навигации от Участника.

Вы должны заполнить данныена основе ваших текущих потребностей или жить с проблемой N + 1.Например, вы можете использовать отдельный запрос linq:

var clubId = ActiveClub.Id;
var members = (from member in context.Members.Include("Address")
               where member.LeftDate == null and member.ClubId == clubId
               select member).ToList();
...