EF code-first: как загрузить связанные данные (родитель-потомок-внук)?

У меня есть эта сущность:

public class DynamicPage {

    public int PageId { get; set; }

    public int Order { get; set; }

    public string MenuText { get; set; }

    public string MenuHover { get; set; }

    public int? ParentId { get; set; }

    public virtual DynamicPage Parent { get; set; }

    public virtual ICollection<DynamicPage> Children { get; set; }
}

Эта сущность может иметь 3 уровня: Родитель -> Дочерний элемент -> Внук. Как я могу загрузить родителя (уровень 1) со всеми связанными дочерними элементами (уровень 2) и для каждого ребенка связанным внуком (уровень 3), если таковые имеются? Спасибо за помощь.




Ответы (2)


Функция и синтаксис EF 4.1:

var entity = context.Parents
    .Include(p => p.Children.Select(c => c.GrandChildren))
    .FirstOrDefault(p => p.Id == 1); // or whatever condition
person Slauma    schedule 22.09.2011
comment
Не существует свойства с именем GrandChildren. Вы имеете в виду этот код: Include(p => p.Children.Select(c => c.Children)) ? - person amiry jd; 23.09.2011
comment
@Javad_Amiry: Да. На самом деле то, что я написал как GrandChildren, может быть любым навигационным свойством — коллекцией или ссылкой. Шаблон Include(x => x.SomeCollection.Select(c => c.SomeNavigationProperty)) просто вызывает Include для следующего уровня. Вы можете повторять это до бесконечности: Select для коллекций, простые пунктирные пути для ссылок. - person Slauma; 23.09.2011
comment
Хорошо, это работает правильно: D большое спасибо. В продолжении мне нужно заказывать детей (и, следовательно, внуков) при их извлечении. Я отредактирую ваш ответ и вставлю свой первый код и окончательный код, созданный под вашим руководством, чтобы объяснить мою проблему. Пожалуйста, помогите мне завершить решение. Особая благодарность обратить внимание на вопрос. С Уважением - person amiry jd; 23.09.2011
comment
@Javad_Amiry: Лучше задайте новый вопрос о вашей проблеме с сортировкой, потому что 1) больше людей увидят новый вопрос, чем редактирование в моем ответе, и 2) я сейчас не в сети :) - person Slauma; 23.09.2011
comment
Хорошо, прежде чем я увижу ваш комментарий, я опубликую свою правку. Так жаль. Я задам новый вопрос прямо сейчас. Пожалуйста, отмените мою правку, SOF не позволяет мне делать это самостоятельно. Еще раз спасибо. - person amiry jd; 23.09.2011
comment
Изменилось ли это в EF4.3? Единственная версия .Include(), которую я вижу в 4.3, принимает строку вместо навигатора с безопасным типом, например x => x.Children — шаг назад. Это отражено в документации здесь: asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-4 Кажется странным идти назад в более новой версии фреймворка... - person Chris Moschini; 03.03.2012
comment
@ChrisMoschini: Нет, ничего не изменилось. Перегрузка выражения Include все еще существует. Убедитесь, что вы включили using System.Data.Entity; в исходный файл. - person Slauma; 03.03.2012

Если вы хотите облегчить себе жизнь, следуйте соглашениям EF Code First, называя идентификаторы таблиц просто Id (или, альтернативно, имя таблицы + Id, например, DyanmicPageId).

Это должно оставить вас с чем-то вроде этого:

public class DynamicPage
{
    public int Id { get; set; }
    public int Order { get; set; }
    public string MenuText { get; set; }
    public string MenuHover { get; set; }
    public int? ParentId { get; set; }

    public virtual DynamicPage Parent { get; set; }
    public virtual ICollection<DynamicPage> Children { get; set; }
}

Затем вам нужно явно установить отношения между родителями и детьми в методе OnModelCreating в вашем классе DbContext.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<DynamicPage>()
        .HasMany(page => page.Children)
        .WithRequired(child => child.Parent)
        .HasForeignKey(child => child.ParentId);
}

Затем вы можете выбрать детей или внуков по мере необходимости:

var parent = dbContext.DynamicPages.Where(page => page.ParentId == null);
var children = parent.Children;
var grandchildren = parent.SelectMany(page => page.Children);
var allRelatedPages = parent.Union(children).Union(grandchildren);
person devuxer    schedule 22.09.2011
comment
О чем ты говоришь? Пожалуйста, прочитайте вопрос еще раз: Как я могу загрузить родительский элемент (уровень 1) со всеми связанными дочерними элементами (уровень 2) и для каждого дочернего элемента связанный внук (уровень 3), если таковой имеется? Я знаю, как сопоставить объекты и знать, как загружать их в двухуровневом отношении Parent-Child. Но я не могу загрузить 3-уровневую ассоциацию. Только это! - person amiry jd; 22.09.2011
comment
Что вы имеете в виду под нагрузкой? Вы имеете в виду выбрать? - person devuxer; 22.09.2011
comment
Загрузить из базы данных, получить из базы данных, выбрать. Вот так: entity.DynamicPages.Where(d => d.ParentId == null).Include(d => d.Children).ToList(); я это знаю, но хочу загрузить d.Children.Children то, что не могу ): - person amiry jd; 22.09.2011
comment
Обновил мой ответ. Надеюсь, это то, что вы искали. - person devuxer; 22.09.2011
comment
Спасибо, проверю и выложу сюда результат. С Уважением - person amiry jd; 22.09.2011
comment
Что ж, в таком случае вам просто нужно объединить их вместе. Я снова обновил свой ответ. - person devuxer; 22.09.2011
comment
Спасибо, что обратили внимание на мой вопрос, но мой ответ не такой, и из-за того, что я плохо говорю по-английски, я не могу объяснить свою цель. С Уважением - person amiry jd; 23.09.2011
comment
Теперь, когда я вижу ответ Слаумы, я понимаю, что вы искали. И я тоже кое-чему научился, так что никаких проблем. - person devuxer; 23.09.2011
comment
Я переместил часть 2 вопроса (заказ детей и внуков) сюда: stackoverflow.com/questions/7522784/ Я будьте благодарны, если увидите новый вопрос и предложите мне, если у вас есть какие-либо идеи. Хороший замок и с наилучшими пожеланиями. - person amiry jd; 23.09.2011