When to use Include in EF? Not needed in projection?

entity-framework entity-framework-core

Question

I have the following in Entity Framework Core:

public class Book {
  public Int32 Id { get; set; }
  public String Title { get; set; }
  public virtual Theme Theme { get; set; }
}

public class Theme {
  public Int32 Id { get; set; }
  public String Name { get; set; }
  public Byte[] Illustration { get; set; }
  public virtual ICollection<Ebook> Ebooks { get; set; }
}

And I have the following linq query:

List<BookModel> books = await context.Books.Select(x =>
  new BookModel {
    Id = x.Id,
    Name = x.Name,
    Theme = new ThemeModel {
      Id = x.Theme.Id,
      Name = x.Theme.Name
    }
   }).ToListAsync();

I didn't need to include the Theme to make this work, e.g:

List<BookModel> books = await context.Books.Include(x => x.Theme).Select(x => ...

When will I need to use Include in Entity Framework?

UPDATE

I added a column of type Byte[] Illustration in Theme. In my projection I am not including that column so will it be loaded if I use Include? Or is never loaded unless I have it in the projection?

Accepted Answer

You didn't need Include because you were working inside EF context. When you reference Theme inside the anonymous object you are creating, that's not using lazy loading, that's telling EF to do a join.

If you return a list of books and you don't include the themes, then when you try to get the theme you'll notice that it's null. If the EF connection is open and you have lazy loading, it will go to the DB and grab it for you. But, if the connection is not opened, then you have to get it explicitely.

On the other hand, if you use Include, you get the data right away. Under the hood it's gonna do a JOIN to the necessary table and get the data right there.

You can check the SQL query that EF is generating for you and that's gonna make things clearer for you. You'll see only one SQL query.


Popular Answer

If you Include a child, it is loaded as part of the original query, which makes it larger.

If you don't Include or reference the child in some other way in the query, the initial resultset is smaller, but each child you later reference will lazy load through a new request to the database.

If you loop through 1000 users in one request and then ask for their 10 photos each, you will make 1001 database requests if you don't Include the child...

Also, lazy loading requires the context hasn't been disposed. Always an unpleasant surprise when you pass an Entity to a view for UI rendering for example.

update Try this for example and see it fail:

var book = await context.Books.First();
var theme = book.Theme;

Then try this:

var book = await context.Books.Include(b => b.Theme).First();
var theme = book.Theme;


Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow