c# - 什么时候需要在 Entity Framework 中包含相关实体?

标签 c# entity-framework

当我必须实际 .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()

此方法获取指定公司的所有已批准的时间表条目。此 View 模型专门用于操作发票的时间表条目关联时(因此您可以根据所选的时间表条目开具发票)。

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

将时间表实体映射到 View 模型的工厂中发生 NullReferenceExceptions:

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 有时很乐意为我提供数据,而无需我显式请求该数据,有时又要求我显式请求数据,否则会引发错误?

我如何知道何时需要明确包含我正在查找的数据,何时不需要?

最佳答案

Entity Framework 使用延迟加载来加载子关系。 要使模型中的延迟加载工作属性应使用 virtual 关键字进行标记。 Ef 会覆盖它并添加延迟加载支持。

当您没有虚拟属性时,EF 无法稍后加载您的子关系数据,因此唯一可能的情况是 - 在使用 Include 初始数据加载期间。

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

关于c# - 什么时候需要在 Entity Framework 中包含相关实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55454839/

相关文章:

c# - Entity Framework 查询思路(group by)

c# - EF :6 - How to skip insertion of value if value has default value set in DB?

entity-framework - 首先将文档添加到 Entity Framework 模型中的生成代码中

c# - Entity Framework ALTER TABLE 语句与 FOREIGN KEY 约束冲突

c# - 在 Gtk# 中,如何重置使用 GLib.Timeout.Add 设置的计时器?

c# - 为什么可空的模式匹配会导致语法错误?

c# - 在 C# 中使用 DataContractJsonSerializer 使用 List<> 反序列化 JSON 对象

c# - EF Core 如何选择具有多对多关系的实体

c# - 使用 linq 和 lambda 对列表进行分组和展平

c# - 从 SOAP 消息中提取 SOAP 主体