Агрегатная навигация от корня до дочерней сущности с использованием Entity Framework 4

Я пытаюсь применить шаблон совокупного корня к своему домену. Я использую Entity Framework 4 с генератором сущностей POCO.

У меня есть две сущности: MailingTask EmailLog с отношением «один ко многим». (MailingTask имеет множество журналов электронной почты). EF4 создает свойство навигации в MailingTask:

public virtual ICollection<EmailLog> EmailLogs

В моей модели я никогда не хочу напрямую обращаться к EmailLogs, всегда через его родительский MailingTask. Это обеспечивается:

  • Имея только репозиторий MailingTask, поэтому я не могу напрямую запросить таблицу EmailLogs.
  • Получение журналов электронной почты только через это свойство навигации.

Иногда мне нужно подсчитать количество журналов электронной почты для MailingTask. Это достигается с помощью LINQ в свойстве навигации:

mailingTask.EmailLogs.Count();

Но это выполняется на стороне приложения (а не на сервере базы данных). (И это очень дорого, поскольку у меня много журналов электронной почты для MailingTask.) Я прочитал несколько сообщений об этом поведении, и похоже, что свойства навигации EF4 не могут использоваться как IQueryable (выполняются на стороне базы данных). При доступе к свойству навигации EF4 загружает ВСЕ записи со ВСЕМИ столбцами в памяти и применяет выражение LINQ в памяти. Для оператора Count () это очень больно.

Я считаю, что мне придется изменить мою модель, чтобы приспособить этот специализированный запрос (возможно, добавив EmailLogsRepository с возможностями запросов). Мне кажется, что EF4 не очень хорошо поддерживает шаблон Aggregate Root. Или, может быть, мне что-то не хватает о шаблоне агрегированного корня и о том, как его следует реализовать в отношении EF4 ...

Кто-нибудь сталкивался с такой ситуацией и смог ее решить? Поддерживает ли это nHibernate или другой ORM лучше?


person Patrick M    schedule 09.05.2011    source источник


Ответы (1)


NHibernate поддерживает Count() "изначально", так как он сопоставляется с запросом SQL "Select COUNT (*) .." и не требует, чтобы все сущности были материализованы - это то, что EF будет делать с тем же запросом.

Для Entity Framework есть обходной путь для достижения того же, который подробно описан здесь. Тогда запрос для подсчета будет выглядеть примерно так:

int logCount = context.Entry(mailingTask)
                      .Collection(p => p.EmailLogs)
                      .Query()
                      .Count();

Это потребует изменения модели для этого одного запроса, поскольку вы не можете напрямую работать со свойством навигации / Count(), что является серьезным недостатком и что-то, что необходимо как можно скорее исправить в EF.

person BrokenGlass    schedule 09.05.2011
comment
Меня расстраивает изменение модели для раскрытия контекста. Спасибо за альтернативу с использованием DbContext, но переход на NHibernate, вероятно, будет тем путем, по которому я пойду, хотя это будет тяжелая работа. - person Patrick M; 09.05.2011