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

How to explicit loading long navigation properties' chain using Entity Framework?

我有这段代码可以显式加载实体:

dbContext.StorageRequests.Add(storageRequest);
dbContext.SaveChanges();
//Here I want to explict loading some navigation properties
dbContext.Entry(storageRequest).Reference(c => c.Manager).Load();
dbContext.Entry(storageRequest).Reference(c => c.Facility).Load();
dbContext.Entry(storageRequest).Collection(x=> x.PhysicalObjects).Query().Include(x => x.Classification).Load();

我的问题分为两部分:

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

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

我对 EF 核心有类似的问题。打开 SQL 记录到 debugoutput window 帮助回答了我的很多问题,关于它在做什么,为什么。针对您的问题:

1) 你不能,尽管你可以使用一系列 dbContext.Collection.Include(otherCollection).ThenInclude(stuffRelatedToOtherCollection) 类型链

预先加载它

2) 是的,即使在一个 c# 语句中预先加载也会引发多个查询。我认为这是因为除了最简单的倍数 sql 之外,它是一个太复杂的人工智能问题,无法以任何方式解决,因为当多个表连接在一起时,框架很难处理笛卡尔积一个矩形数据集。 (一个学校有学生和老师,teacher:students是many:many关系,分解为class。如果你写一个查询加入学校,class,学生和老师,你到处都是重复的数据,虽然从概念上讲可以通过它来寻找独特的学校,class 老师和学生的主键值,但您可能会下载数万个重复的行,只需要对它们进行唯一处理又一次。EF倾向于select学校,然后学校加入class,然后学校加入class加入学生,然后学校加入class加入教师(如果你是这样编码的您的学校包括 class 然后包括学生然后包括教师。更改您的包括策略将更改 运行)

的查询

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

2.)

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

A query is executed against the database when:


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

in most cases, EF will combine the joins when generating 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() 一起使用。 您可以检查它是否:

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

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

Multiple network roundtrips can degrade performance, especially where latency to the database is high (for example, cloud services).


兴趣点:

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

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

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

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