实体框架 - 使用长链依赖对象进行高效的热切加载?

Gau*_*ver 5 c# linq asp.net-mvc performance entity-framework

我有一个问题,我认为很多专业开发人员会遇到这个问题.我的工作场所采用了实体框架.我们使用它,并喜欢它.但是,我们似乎遇到了一个非常令人沮丧的限制.

我们假设您有一个对象链

A - > B - > C - > D.

我们是专业人士,因此这些对象拥有大量数据,并且在各自的数据库表中有很多数据.看起来EF在加载任何超过对象B的东西时都会遇到很糟糕的时间.它生成的SQL查询效率非常低且不好.电话会是这样的

context.objects.include("bObjectName.cObjectName.dObjectName").FirstOrDefault(x => x.PK == somePK);
Run Code Online (Sandbox Code Playgroud)

我们通过使用.Load()命令显式加载超过第二级的对象来解决这个问题.这适用于单个对象.但是,当我们谈论一组对象时,我们开始遇到.Load()的问题.

首先,似乎没有办法在没有virtual关键字的情况下保持集合中对象的代理跟踪.这是有道理的,因为它需要覆盖get和set函数.但是,这会启用延迟加载,并且.Load()在启用延迟加载时不会映射实体.我觉得这有些奇怪.如果删除虚拟关键字,.Load()会自动将加载的对象链接到上下文中的相关对象.

所以这是我的问题的关键.我想要代理跟踪,但也希望.Load()为我映射导航属性.如果EF可以生成良好的查询,这些都不会成为问题.我理解为什么它不能,它必须是一个适合所有类型的东西.

因此,要加载第三层对象,我可以在服务层中创建一个加载器函数,它接受第二层对象的所有主键,然后在它们上调用.Load().有人有解决方案吗?好像EF7或Core 1.0通过以下方式解决了这个问题:

  1. 完全删除延迟加载,我们也可以关闭它,但它会打破很多旧的代码.
  2. 添加一个新的"ThenInclude"功能,据说可以提高链接的效率,包括大量的功能.

如果关闭延迟加载是答案,那很好,我只想浪费所有选项,然后浪费大量时间重新开发一个巨大的webapps值得服务电话.有没有人有任何想法?我愿意付出一些代价.我们正在使用EF6.

编辑:似乎答案是在上下文级别关闭延迟加载,或升级到EF7.如果其他人设法找到一个解决方案,你可以通过强制急切加载EF6的单个对象进行代理跟踪,我会改变这个.

Tom*_*ord 1

您对链接的 .Include() 语句的看法绝对正确,性能文档警告不要链接超过 3 个语句,因为每个 .Include() 添加一个外部联接或联合。我不知道 ThenInclude,但它听起来像是一个游戏规则改变者!

如果保留虚拟导航属性但关闭 DbContext 上的延迟加载

 context.ObjectContext().ContextOptions.LazyLoadingEnabled = false;
Run Code Online (Sandbox Code Playgroud)

然后(只要启用了更改跟踪)您可以执行以下操作:

var a = context.aObjectNames.First(x=> x.id == whatever);

context.bObjectNames.Where(x=> x.aId == a.Id).Load()
Run Code Online (Sandbox Code Playgroud)

这应该填充 a.bObjects