Когда вам нужно. Включать связанные объекты в Entity Framework? - PullRequest
1 голос
/ 01 апреля 2019

Это кажется мне произвольным, когда мне приходится иметь дело с .Include() связанными сущностями, а когда нет. В некоторых случаях EF дает мне информацию о связанных объектах без нее, а в других случаях он ничего не может сделать со связанными объектами, потому что я их не включил:

Работает без .Include ();

Это пример, когда я загружаю данные без .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.
    }
}

Ниже приведен результат, включающий данные для компании, связанные с запрашиваемым счетом: enter image description here

Как видите, информация для компании определенно поступает, но не была явно включена.

Не работает без .Include ();

И наоборот, я сделал некоторое сопоставление со счетами в этом же проекте, и я получил NullReferenceExceptions при извлечении значений свойств связанных сущностей, потому что я не .Include().

Этот метод получает все утвержденные записи расписания для указанной компании. Эта модель представления предназначена исключительно для управления связью записей расписания для счета-фактуры (поэтому вы выставляете счета на основании выбранных записей расписания).

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

Исключения NullReferenceException возникли на фабрике, которая отображает сущности расписания в модель представления:

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

Чтобы исправить это, мне пришлось изменить запрос, извлекающий данные, на следующий:

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

Почему Entity Framework иногда с радостью предоставляет мне данные, а я явно не запрашиваю эти данные, а иногда мне требуется явно запросить данные, иначе выдается ошибка?

А как мне узнать, когда мне нужно явно включить данные, которые я ищу, а когда нет?

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

Это зависит от ваших моделей.Если вы отметили реляционные свойства как virtual, вам нужно будет использовать .Include, чтобы EF знала, что вам это нужно.Это Ленивая Загрузка.Сохраняет память машины и запросы БД.

1 голос
/ 01 апреля 2019

Entity Framework использует ленивую загрузку для загрузки дочерних отношений. Для отложенной загрузки на работу свойство в модели должно быть помечено ключевым словом virtual. Ef переопределяет его и добавляет поддержку отложенной загрузки.

Когда у вас нет виртуального свойства, EF не имеет возможностизагрузите данные о ваших дочерних отношениях позже, так что единственный раз, когда это возможно - во время начальной загрузки данных, используя Include.

public class Timesheet
{
    ...
    public virtual StaffMember StaffMember { get; set; }
    public virtual Task Task { get; set; }
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...