When do you need to .Include related entities in Entity Framework?

Ortund

This seems arbitrary to me when I have to actually .Include() related entities and when I don't. In some cases, EF gives me the info for the related entities without it and in other cases, it can't do anything with the related entities because I didn't include them:

Works without .Include();

This is an example where I'm loading data without .Include();

public class InvoiceService
{
    private ApplicationDbContext db { get; set; }
    public InvoiceService(ApplicationDbContext context)
    {
        db = context;
    }

    public Invoice Get(int id)
    {
        return db.Invoices.SingleOrDefault(x => x.Id == id);
    }
}

public partial class ShowInvoice : System.Web.UI.Page
{
    private InvoiceService invoiceService;

    private readonly ApplicationDbContext context = new ApplicationDbContext();
    protected void Page_Load(object sender, EventArgs e)
    {
        invoiceService = new InvoiceService(context);
        if (!IsPostBack)
        {
            int.TryParse(Request.QueryString["invoiceId"].ToString(), out int invoiceId);
            LoadInvoice(invoiceId);
        }
    }

    private void LoadInvoice(int invoiceId)
    {
        var invoice = invoiceService.Get(invoiceId);
        // Other code irrelevant to the question goes here.
    }
}

Here follows the result which includes the data for the Company associated with the invoice I'm requested: enter image description here

As you can see, the information for the company definitely comes through but was not explicitly included.

Doesn't work without .Include();

Conversely, I've done some mapping to do with invoices in this same project and I got NullReferenceExceptions when fetching the related entities property values because I didn't .Include().

This method gets all the approved timesheet entries for the specified company. This viewmodel is exclusively to be used when manipulating the association of timesheet entries for an invoice (so you're invoicing based on the timesheet entries selected).

public List<InvoiceTimesheetViewModel> GetInvoiceTimesheetsByCompanyId(int companyId)
{
    var factory = new TimesheetViewModelsFactory();

    var timesheets = db.Timesheets.Where(x => x.Approved && x.Company.Id == companyId && !x.Deleted).ToList();
    return factory.GetInvoiceTimesheetsViewModel(timesheets);
}

NullReferenceExceptions occurred in the factory that maps the timesheet entities to the viewmodel:

public List<InvoiceTimesheetViewModel> GetInvoiceTimesheetsViewModel(List<Timesheet> timesheets)
{
    var model = new List<InvoiceTimesheetViewModel>();
    foreach (var timesheet in timesheets)
    {
        var start = DateTime.Parse((timesheet.DateAdded + timesheet.StartTime).ToString());
        var finished = DateTime.Parse((timesheet.DateCompleted + timesheet.EndTime).ToString());
        DateTime.TryParse(timesheet.RelevantDate.ToString(), out DateTime relevant);

        model.Add(new InvoiceTimesheetViewModel
        {
            RelevantDate = relevant,
            BillableHours = timesheet.BillableHours,
            Finished = finished,
            Id = timesheet.Id,
            StaffMember = timesheet.StaffMember.UserName, // NRE here.
            Start = start,
            Task = timesheet.Task.Name // NRE here.
        });
    }
    return model;
}

To fix these, I had to change the query that fetches the data to the following:

var timesheets = db.Timesheets.Include(i => i.StaffMember).Include(i => i.Task)
            .Where(x => x.Approved && x.Company.Id == companyId && !x.Deleted).ToList();

Why is Entity Framework sometimes happy to give me data without me explicitly requesting that data and sometimes it requires me to explicitly request the data or else throws an error?

And how am I to know when I need to explicitly include the data I'm looking for and when I don't?

3615

Entity framework uses lazy loading to load child relationships. For lazy loading to work property in the model should be marked with virtual keyword. Ef overrides it and adds lazy loading support.

When you have no virtual property EF has no way to load your child relationship data later, so the only time it's possible to do - during initial data loading using Include.

public class Timesheet
{
    ...
    public virtual StaffMember StaffMember { get; set; }
    public virtual Task Task { get; set; }
    ...
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Entity Framework 5 - Apply filter loading related entities using Include

How to include related entities in an Entity Framework Core 1.0.1 raw query?

Entity Framework Include aren't including related entities

Entity Framework Loading Related Entities

Entity Framework does not load related data when entities are not public

Entity Framework is lazy loading related entities when nav properties are not accessed

How do you update parent entities LastUpdate property when adding or changing a child at any level in the hierarchy below it in Entity Framework?

Entity Framework query Related Entities in single query

How to load related entities with the Entity Framework Core

Inserting Disconnected Related Entities with Entity Framework 6

Return all related entities with Entity Framework

Why Entity Framework is loading related entities automatically

How to filter by multiple related entities in Entity Framework

Entity Framework Core join & include inner entities

How to filter "Include" entities in entity framework?

Entity Framework LINQ Include - Child Entities

How to include associated entities with Entity Framework?

How do I load related entities from a database view using entity framework?

Using Entity Framework Core 5, how can I automatically updated related entities when calling SaveChanges()?

Entity Framework Core get entity without related entities

Entity Framework Serialize entity to json with included related entities

Entity framework query to include child entities of entity collection

Entity Framework Core error when modifying entities

Entity Framework Many-to-Many not loading related entities

Querying nested/related entities in Entity Framework using Linq

Entity Framework: How to enable cascade delete on one way related entities

Entity Framework adding multiple related entities with single insert

Entity Framework Core GroupBy - aggregate functions on related entities

Entity Framework Core 2.0.1 Eager Loading on all nested related entities