实体框架-“ Attach()”;是慢的 [英] Entity Framework - "Attach()" is slow

查看:65
本文介绍了实体框架-“ Attach()”;是慢的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用EF5,并将断开连接的POCO实体图附加到我的上下文中,如下所示:-

I'm using EF5 and attaching a disconnected graph of POCO entities to my context, something like this:-

using (var context = new MyEntities())
{
    context.Configuration.AutoDetectChangesEnabled = false;

    context.MyEntities.Attach(myEntity);

    // Code to walk the entity graph and set each entity's state
    // using ObjectStateManager omitted for clarity ..

    context.SaveChanges();
}

实体 myEntity是一个大型的实体图,其中包含许多子集合,而后者又拥有自己的子集合,依此类推。整个图形包含大约10000个实体,但是通常只更改少量。

The entity "myEntity" is a large graph of entities, with many child collections, which in turn have their own child collections, and so on. The entire graph contains in the order of 10000 entities, but only a small number are usually changed.

用于设置实体状态和实际 SaveChanges()相当快(<200ms)。问题在于 Attach(),它需要2.5秒,所以我想知道是否可以改进。我看过一些文章,告诉您将 AutoDetectChangesEnabled = false 设置为上述操作,但这对我的情况没有任何影响。为什么会这样呢?

The code to set the entity states and the actual SaveChanges() is fairly quick (<200ms). It's the Attach() that's the problem here, and takes 2.5 seconds, so I was wondering if this could be improved. I've seen articles that tell you to set AutoDetectChangesEnabled = false, which I'm doing above, but it makes no difference in my scenario. Why is this?

推荐答案

我担心,将带有10000个实体的对象图附加2.5秒是正常的。这段时间,可能是当您附上图表时发生的实体快照创建。

I am afraid that 2,5 sec for attaching an object graph with 10000 entities is "normal". It's probably the entity snapshot creation that takes place when you attach the graph that takes this time.

如果通常只更改少量数字(例如100),则可以考虑从数据库中加载原始实体并更改其属性,而不是附加整个图,例如:

If "only a small number are usually changed" - say 100 - you could consider to load the original entities from the database and change their properties instead of attaching the whole graph, for example:

using (var context = new MyEntities())
{
    // try with and without this line
    // context.Configuration.AutoDetectChangesEnabled = false;

    foreach (var child in myEntity.Children)
    {
        if (child.IsModified)
        {
            var childInDb = context.Children.Find(child.Id);
            context.Entry(childInDb).CurrentValues.SetValues(child);
        }
        //... etc.
    }
    //... etc.

    context.SaveChanges();
}

尽管这会创建很多单个数据库查询,但只有扁平实体没有导航属性的对象将被加载和附加(在调用 Find 时发生)不会花费很多时间。为了减少查询数量,您还可以尝试使用包含查询来加载与批处理相同类型的实体:

Although this will create a lot of single database queries, only "flat" entities without navigation properties will be loaded and attaching (that occurs when calling Find) won't consume much time. To reduce the number of queries you could also try to load entities of the same type as a "batch" using a Contains query:

    var modifiedChildIds = myEntity.Children
        .Where(c => c.IsModified).Select(c => c.Id);

    // one DB query
    context.Children.Where(c => modifiedChildIds.Contains(c.Id)).Load();

    foreach (var child in myEntity.Children)
    {
        if (child.IsModified)
        {
            // no DB query because the children are already loaded
            var childInDb = context.Children.Find(child.Id);
            context.Entry(childInDb).CurrentValues.SetValues(child);
        }
    }

在您只假设必须更改实体的标量属性。如果涉及到对关系的修改(已将孩子添加到集合中和/或从集合中删除了孩子等),它可能会变得更加复杂。

It's just a simplified example under the assumption that you only have to change scalar properties of the entities. It can become arbitrarily more complex if modifications of relationships (children have been added to and/or deleted from the collections, etc.) are involved.

这篇关于实体框架-“ Attach()”;是慢的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆