如何使用Entity Framework显式加载长导航属性链?

时间:2017-11-30 09:46:16

标签: c# performance entity-framework lazy-loading

我有这个代码显式加载实体:

<form method="post" action="ModuleQuickMenu.aspx\?mid=65&digest=(.+?)" id="form1">

我的问题分为两部分:

第一个如何一起加载(我想调用Load()一次)?

第二部分上面的代码是否为每个Load()调用发送查询,然后又调用数据库加载相关数据?

2 个答案:

答案 0 :(得分:1)

我有与EB核心类似的问题。将SQL日志记录打开到debugoutput窗口有助于回答我很多关于它正在做什么的问题,以及为什么。就你的问题而言:

1)你不能,虽然你可以用一系列dbContext.Collection.Include(otherCollection).ThenInclude(stuffRelatedToOtherCollection)类型链来急切加载它

2)是的,即使是在一个c#语句中急切加载,也会爆出多个查询。我认为这是因为除了最天真的multi-sql以外,其他任何方式都是一个复杂的人工智能问题,因为当多个表格时框架很难处理笛卡尔积在一个矩形数据集中连接在一起。 (一所学校有学生和老师,老师:学生很多:很多关系,按课程分解。如果你写了一个查询加入学校,班级,学生和老师,你会得到重复的数据到处都是虽然从概念上可以通过它寻找独特的学校,班级老师和学生的主要键值,但你可以下载成千上万的重复行只是为了让它们再次独一无二.EF倾向于选择学校,然后学校加入班级,然后学校加入班级加入学生,然后学校加入班级加入教师(如果您的学校编码方式包括课程,则包括学生,然后包括教师。更改您的包含策略将更改运行的查询)

答案 1 :(得分:1)

好问题!让我以相反的顺序回答不同的问题,提供新信息。

2.)

每个 Load() 都会导致对数据库的查询(Querying and Finding Entities - 2016 年 10 月 23 日):

<块引用>

在以下情况下对数据库执行查询:


人们经常使用 eager loadingInclude() 来让 EF 尽可能地优化:

<块引用>

在大多数情况下,EF在生成SQL时会合并连接

// ef 6
using System.Data.Entity;

var storageRequests = dbContext.StorageRequests
    .Include(r => r.PhysicalObjects.Select(p => p.Classification))
    .Include(r => r.Manager)
    .Include(r => r.Facility);

// evaluate "storageRequests" here by linq method or foreach

或:

// ef core
var storageRequests = dbContext.StorageRequests
    .Include(r => r.PhysicalObjects)
    .ThenInclude(p => p.Classification)
    .Include(r => r.Manager)
    .Include(r => r.Facility);

// evaluate "storageRequests" here by linq method or foreach

1.)

我能想象的唯一可能的方法是将上面的代码与 storageRequests.Load() 一起使用。 你可以检查它是否:

  • 生成单个/多个查询,
  • 沿 StorageRequest 加载导航属性数据。

仅供参考:这些查询执行在微软文档中也称为网络往返

<块引用>

多次网络往返会降低性能,尤其是在数据库延迟很高的情况下(例如,云服务)。


兴趣点:

.Net Core 5 中有一个相对新的选项 Single vs. Split Queries (10/03/2019)。

默认为单个查询(上述行为)。之后,您可以决定改为请求/加载每个表的数据,方法是在评估之前将 .AsSplitQuery() 添加到您的 linq 查询。拆分查询会增加往返次数和内存使用量(不加载不同的数据),但有助于提高性能。

还有 .AsSingleQuery() 如果 your global choice 是:

.UseSqlServer(
    connectionString,
    o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery));