Dave Zych
Dave Zych

Reputation: 21887

Include not including navigation property unless ToList is called

I'm using EF7 beta 7. I have a few forum style tables with a navigation property between them, along with a relationship set up in the OnModelCreating method of the context:

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);
    }
}

I'm trying to get a list of Forum with a count of the Topic:

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

When I run this as is, I get an ArgumentNullException I get an empty collection because it doesn't seem to actually eagerly load the Topics. I have checked in Sql Profiler and confirmed that it's only running the select to get the Forum's and no second select for the Topic's.

If I call ToList before the Select as such

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

it will include the Topic's and the code runs, however that defeats the purpose because that causes it to enumerate all forums with all topics and then count, instead of running the Count on the database. Is this a bug with Include, or am I using Include wrong?

Upvotes: 1

Views: 976

Answers (1)

natemcmaster
natemcmaster

Reputation: 26773

You need to configure the relationship between Topics and Forum for .Include to work.

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

See How to work with collections for more tips on using collections.

Another note

By calling .ToList() immediately after .Include(...) you are forcing an early evaluation. The following projection in .Select(...) runs in-memory on the client side, rather than using EF7's query pipeline.

Also, make sure to add an initializer into your POCO definition.

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

Upvotes: 1

Related Questions