Подтвердить что ты не робот

Использование Include() с унаследованными объектами

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

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

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

Сущности:

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

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

На самом деле мои пользователи всегда имеют тип UserSpecial, поскольку UserBase используется в другом приложении, поэтому мы можем делиться учетными данными. Это единственная причина, у меня есть две отдельные таблицы. Таблица 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, но они не загружают объекты в контекст (я полагаю).

4b9b3361

Ответ 1

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

В вашем случае, включая соответствующие свойства UserCreated и UserEdited в проекции, это правильное решение. Однако, если вы также хотите заполнить свойство Изображение объекта 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 и Изображение. Вместо этого вам просто нужно получить доступ к свойствам навигации объектов ArticleSpecial во время фазы проектирования, чтобы заставить Entity Framework с нетерпением загружать связанные объекты.