Использование Include () с унаследованными сущностями - PullRequest
12 голосов
/ 23 февраля 2010

В EF полная загрузка связанных объектов easy .

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

Это моя модель:

Сущности

  • ArticleBase (сущность базового товара)
    • ArticleSpecial (унаследовано от ArticleBase)
  • UserBase (базовый пользовательский объект)
    • UserSpecial (унаследовано от UserBase)
  • Image

Отношения такие, как показано на рисунке (пропущено много столбцов): alt text

На самом деле мои пользователи всегда имеют тип UserSpecial, поскольку UserBase используется в другом приложении, поэтому мы можем обмениваться учетными данными. Это единственная причина, по которой у меня есть две отдельные таблицы. UserBase Таблица не может быть изменена каким-либо образом, потому что другое приложение сломалось бы.

Вопрос

Как мне загрузить ArticleSpecial с обоими CreatedBy и EditedBy, чтобы оба типа UserSpecial (которые определяют отношение Image)?


Я пробовал (но безуспешно) следующие опции:

1. Использование лямбда-выражений:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated.Image")
    .Include("UserEdited.Image");

В этом случае проблема в том, что и CreatedBy, и EditedBy связаны с UserBase, который не определяет Image навигацию. Поэтому я должен как-то привести эти два к типу UserSpecial, например:

context.ArticleBases
    .OfType<ArticleSpecial>()
    .Include("UserCreated<UserSpecial>.Image")
    .Include("UserEdited<UserSpecial>.Image");

Но, конечно, использование дженериков в Include("UserCreated<UserSpecial>.Image") не работает.

2. Я пытался использовать запрос LINQ

var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
                  join created in ctx.UserBase.OfType<UserSpecial>().Include("Image")
                  on articleSpecial.UserCreated.Id equals created.Id
                  join edited in ctx.UserBase.OfType<UserSpecial>().Include("Image")
                  on articleSpecial.UserEdited.Id equals edited.Id   
              select articleSpecial;

В этом случае я получаю только ArticleSpecial экземпляров объекта без установки связанных свойств. Я знаю, что должен как-то их выбрать, но не знаю как?

Выберите часть в моем LINQ может быть изменен на что-то вроде

select new { articleSpecial, articleSpecial.UserCreated, articleSpecial.UserEdited };

но изображения все еще не загружены в мой контекст. Мои объединения в этом случае едва используются для фильтрации результатов articleSpecial, но они не загружают объекты в контекст (я полагаю).

1 Ответ

3 голосов
/ 30 марта 2010

Это, кажется, ограничение в текущей версии Entity Framework (1.0). Посмотрите на этот связанный вопрос SO .

В вашем случае правильное решение включает в себя свойства UserCreated и UserEdited в проекции. Однако, если вы также хотите заполнить свойство Image объекта UserSpecial , вы должны обязательно включить его также:

var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
              select new
              {
                  articleSpecial,
                  articleSpecial.UserCreated,
                  ((UserSpecial)articleSpecial.UserCreated).Image,
                  articleSpecial.UserEdited,
                  ((UserSpecial)articleSpecial.UserEdited).Image
              };

Конечно, этот запрос основан на предположении, что все сущности ArticleSpecial всегда ссылаются на сущность UserSpecial , в противном случае приведение не будет выполнено.
Если это предположение не всегда верно, вы можете выразить один и тот же запрос, используя методы расширения LINQ и многострочную лямбда-функцию для выполнения безопасного приведения:

var results = ctx.ArticleBase
                 .OfType<ArticleSpecial>()
                 .AsEnumerable()
                 .Select(a =>
                  {
                      var userCreated = a.UserCreated as UserSpecial;

                      if (userCreated != null)
                      {
                          var image = userCreated.Image;
                      }

                      var userEdited = a.UserEdited as UserSpecial;

                      if (userEdited != null)
                      {
                          var image = userEdited.Image;
                      }

                      return a;
                  });

В последнем примере вам также не нужно включать в результаты UserSpecial и Image сущностей. Вместо этого вам просто нужно получить доступ к свойствам навигации для сущностей ArticleSpecial на этапе проектирования, чтобы заставить Entity Framework активно загружать связанные объекты.

...