实体框架 缓慢筛选关联实体

本文关键字:实体 关联 筛选 缓慢 框架 | 更新日期: 2023-09-27 17:56:26

在实体上填充过滤的子实体集合时,实体框架似乎非常慢 -

我们正在运行一个 RIA/WCF Web 应用,使用用 C# 编写的数据库优先实体框架和 Silverlight 客户端。我们收集了大约 70,000 个"Eval"实体和类似数量的"InCo"实体。每个 Eval 都有一个最多包含 2 个 InCo 实体的子集合。这种关系是一对多的,因此一个评估可以有多个 InCo,但一个 InCo 绑定到一个 Eval。从数据库加载实体集合后,我像这样循环遍历 Evals -

    foreach(Eval eval in Evals)
        if (eval.InCos.Count > 0)
            // Do something

这需要很长时间(分钟)。逐步浏览代码,我发现 Eval 实体上有一个生成的函数 FilterInCos,用于确定 InCo 是否与其关联(在生成的 .Web.g.cs 文件),并将其传递给 Eval 的 InCos EntityCollection 的构造函数,并在首次引用其属性之一时调用以填充该集合

    private bool FilterInCos(InCo entity)
    {
        return (entity.EvalID == this.EvalID);
    }

从我所看到的,为每个 Eval 的 InCos 集合中的每个 InCo 调用 FilterInCos() 函数 - 这是 70,000 个 Evals 中每个 70,000 次调用,导致大约 50 亿次迭代遍历 Evals 并查询每个 Evals 上的 InCos 集合。由于 Eval:InCo 数据库关系为 1:*,因此应该可以遍历 InCo 对象,使用匹配的 EvalID 检索 Eval,并将 InCo 添加到该 Eval 的 InCos 集合中 - 70,000 次迭代。但是,在我看来,似乎没有办法绕过生成的逻辑。我们也不能只将实体集合分配给 Eval 的 InCos 属性,因为它是只读的。

下面是 EF edmx 文件中的相关数据库关系 -

    <Association Name="FK_InCo_Eval">
      <End Role="Eval" Type="AspireEntityModel.Store.Eval" Multiplicity="1">
        <OnDelete Action="Cascade" />
      </End>
      <End Role="InCo" Type="AspireEntityModel.Store.InCo" Multiplicity="*" />
      <ReferentialConstraint>
        <Principal Role="Eval">
          <PropertyRef Name="EvalID" />
        </Principal>
        <Dependent Role="InCo">
          <PropertyRef Name="EvalID" />
        </Dependent>
      </ReferentialConstraint>
    </Association>

下面是 Eval 客户端实体上的 InCos 属性(来自生成的 .Web.g.cs) 与生成的构造函数

    /// <summary>
    /// Gets the collection of associated <see cref="InCo"/> entity instances.
    /// </summary>
    [Association("Eval_InCo", "EvalID", "EvalID")]
    [XmlIgnore()]
    public EntityCollection<InCo> InCos
    {
        get
        {
            if ((this._InCos == null))
            {
                this._InCos = new EntityCollection<InCo>(this, "InCos", this.FilterInCos, this.AttachInCos, this.DetachInCos);
            }
            return this._InCos;
        }
    }

是否有人在数据库优先的 EF 应用程序上发现了类似的行为,并可以建议解决方法?

实体框架 缓慢筛选关联实体

一旦生产数据库开始获得数百万条记录,我就发现了一个非常相似的问题。长话短说:-

首先)除非我正在编写查询,否则我总是使用.ToList() 强制在任何 foreach() 循环之前对数据库进行一次往返。

第二)如果我可以在第一个查询中收集数据,我从不在循环中使用导航属性。

第三)我没有获得非常广泛的结果,而是尝试获取两个单独的列表(使用 .ToList ) 一个 Eval 和一个 InCos,然后执行 Linq.FirstOrDefault() 将它们连接到内存中,但是我必须考虑内存开销和数据传输时间。

在您的情况下,我会修改用于收集 Evals 的选择,如下所示:-

var Evals = from Ev in db.Evals
            select new {
                Ev,
                Cnt = Ev.Incos.Count()
                }
foreach(var Eval in Evals)
if (Eval.Cnt > 0)
    .......
and access the Eval as Eval.Ev

首先,可以通过在查询本身中筛选查询来提高查询效率:

foreach(Eval eval in Evals.Where(e => e.InCos.Any())

这会将所有筛选移动到服务器,因此不需要对每个Eval记录进行额外的昂贵查询。

如果您需要对InCos执行某些操作,则应急切地加载它们:

foreach(Eval eval in Evals.Expand("InCos").Where(e => e.InCos.Any())