实体框架,预先加载和大对象图

本文关键字:对象图 加载 框架 实体 | 更新日期: 2023-09-27 17:56:22

我有一个WPF项目,它处理带有项目的本地数据库。本地数据库稍后与服务器同步。每个项目都有多个系统,每个系统都有多个"标签"。标签有一个产品,产品由多种材料组成,结构相当先进。一个简单的结构是这样的:

  • 项目
    • 系统
      • 标签
        • 产品
          • 材料 1
          • 材料 2
          • 材料 3
        • 代码要求
      • 系统要求

我现在有两个问题必须解决。

    当项目加载
  1. 时,我需要从数据库加载整个项目并使用本地副本,直到用户保存它。当我尝试急切加载时,它将花费很长时间,我发现您不应该包含很多内容,因为它对性能不利。是否有如何将深层结构加载到内存中的好做法?

  2. 我需要将其加载到内存中的原因是,用户可以处理副本,然后在给定点将其保存到数据库中。我有多个计算函数,取决于树的不同部分。我的结论让我认为我需要将整个项目(或至少是一个系统)发布到业务层,因为所有数据都可以在本地(内存)编辑

我是不是想错了?也许有一种方法可以将整个数据库(因为它不是那么大并且已经是本地的)加载到 memorydb 中,并在实体框架中具有本地上下文。当用户保存时,我将其保存到真实数据库,然后进行同步。

正如你听到的,我不确定如何解决这个问题,所以欢迎任何提示

实体框架,预先加载和大对象图

使用 .包含 在 N:M 关系中,实体框架执行左外联接,返回的行可能远远超过实际需要的行数。

有一种技术可以更精确地加载对象图。 它有很多编码并且非常丑陋,但可以提供更好的性能。 本博客中详细描述了该技术(带有示例)。

我的技术是每个级别查询一次,然后链接应用程序中的对象。

这种技术在其他ORM中是自动的(懒惰的),如NHibernate作为"批处理加载",但在EntityFramework中,您必须手动完成。

我遇到了和你一样的问题,我用大量 Include 语句解决问题的方式是将它们分成小组。

取而代之的是:

scarRevision = db.ScarRevisions
.Include(s => s.Author)
.Include(s => s.Scar.Author)
.Include(s => s.Scar.LockedBy)
.Include(s => s.Scar.Part)
.Include(s => s.Scar.Supplier)
.Include(s => s.ScarGeneralSection.GeneralSectionAttachments)
.Include(s => s.ScarGeneralSection.SupplierContacts.Select(sc => sc.Contact))
// on and on and on...
.FirstOrDefault(s => s.Scar.ScarNumber == scarNumber && s.RevisionNumber == revisionNumber);

我使用这个:

scarRevision = db.ScarRevisions
.Include(s => s.Author)
.Include(s => s.Scar.Author)
.FirstOrDefault(s => s.Scar.ScarNumber == scarNumber && s.RevisionNumber == revisionNumber);
scarRevision = db.ScarRevisions
.Include(s => s.Scar.LockedBy)
.Include(s => s.Scar.Part)
.FirstOrDefault(s => s.Scar.ScarNumber == scarNumber && s.RevisionNumber == revisionNumber);
scarRevision = db.ScarRevisions
.Include(s => s.Scar.Supplier)
.FirstOrDefault(s => s.Scar.ScarNumber == scarNumber && s.RevisionNumber == revisionNumber);

它将我的查询从近 20 秒减少到仅 3 秒。还是有点太多了,但比以前好了近10倍。