实体框架 - "附加()"是慢的

时间:2013-04-30 15:51:59

标签: entity-framework

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

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个实体的顺序,但通常只更改一小部分。

设置实体状态和实际SaveChanges()的代码相当快(<200ms)。这是问题Attach(),需要2.5秒,所以我想知道这是否可以改进。我已经看过一些文章,告诉你设置AutoDetectChangesEnabled = false,我正在上面做,但它在我的场景中没有任何区别。这是为什么?

1 个答案:

答案 0 :(得分:2)

我担心附加10000个实体的对象图形为2.5秒是“正常”。这可能是您附加花费此时间的图表时发生的实体快照创建。

如果“通常只更改一小部分” - 比如100 - 您可以考虑从数据库加载原始实体并更改其属性而不是附加整个图形,例如:

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时发生这种情况)不会消耗太多时间。要减少查询次数,您还可以尝试使用Contains查询加载与“批处理”相同类型的实体:

    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);
        }
    }

这只是一个简化的例子,假设您只需要更改实体的标量属性。如果涉及对关系的修改(从集合中添加和/或删除子项等),它可能会变得任意复杂。