Включить, не включая свойство навигации, если не вызывается ToList

Я использую EF7 beta 7. У меня есть несколько таблиц стилей форума со свойством навигации между ними, а также отношение, установленное в методе OnModelCreating контекста:

public class Forum
{
    public int ForumId { get; set; }
    public string Title { get; set; }

    public ICollection<Topic> Topics { get; set; } =  new List<Topic>();
}

public class Topic
{
    public int TopicId { get; set; }
    public string Title { get; set; }

    public int ForumId { get; set; }
    public Forum Forum { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Forum> Forums { get; set; }
    public DbSet<Topic> Topics { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Forum>()
                    .Collection(f => f.Topics)
                    .InverseReference(t => t.Forum)
                    .ForeignKey(t => t.ForumId);
    }
}

Я пытаюсь получить список Forum с количеством Topic:

var forums = _context.Forums.Include(f => f.Topics)
                            .Select(f => new 
                                {
                                    f.Title,
                                    f.ForumId,
                                    f.Topics.Count
                                });

Когда я запускаю это как есть, я получаю ArgumentNullException, я получаю пустую коллекцию, потому что на самом деле она не загружает Topics. Я проверил Sql Profiler и подтвердил, что выполняется только выбор для получения Forum и нет второго выбора для Topic.

Если я позвоню ToList перед Select как таковым

var forums = _context.Forums.Include(f => f.Topics)
                            .ToList()
                            .Select(f => new 
                                {
                                    f.Title,
                                    f.ForumId,
                                    f.Topics.Count
                                });

он будет включать Topic, и код запускается, однако это противоречит цели, потому что это приводит к тому, что он перечисляет все форумы со всеми темами и затем подсчитывает вместо запуска Count в базе данных. Это ошибка с Include, или я неправильно использую Include?


person Dave Zych    schedule 04.09.2015    source источник
comment
Я не работал с EF7, только 6, поэтому, возможно, он изменился, но разве ваше свойство навигации не должно быть virtual, чтобы поддерживать как активную, так и ленивую загрузку?   -  person dmeglio    schedule 04.09.2015
comment
@ dman2306 Я только что попытался сделать их virtual, и никаких изменений. Я не думаю, что это требуется и в EF 6...   -  person Dave Zych    schedule 04.09.2015


Ответы (1)


Чтобы .Include работало, необходимо настроить связь между темами и форумом.

class YourContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
          // configure the relationship here
    }
}

Дополнительные советы по использованию коллекций см. в разделе Как работать с коллекциями.

Еще одно примечание

Вызывая .ToList() сразу после .Include(...), вы форсируете раннюю оценку. Следующая проекция в .Select(...) выполняется в памяти на стороне клиента, а не с использованием конвейера запросов EF7.

Кроме того, не забудьте добавить инициализатор в определение POCO.

public ICollection<Topic> Topics { get; set; } = new List<Topic>()
person natemcmaster    schedule 04.09.2015
comment
Тот другой пост SO великолепен, спасибо, однако, похоже, он не помогает. Я добавил отношение и инициализировал коллекцию, но все равно получаю тот же результат (хотя и пустую коллекцию вместо NRE). Я отредактировал соответствующие изменения в вопросе. - person Dave Zych; 04.09.2015
comment
Вы знаете, похоже, что отношения работают, это проекции, которые не... Я собираюсь задать новый вопрос по этому поводу. Спасибо. - person Dave Zych; 05.09.2015