实体框架 - "Attach()"很慢

And*_*ens 6 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();
}
Run Code Online (Sandbox Code Playgroud)

实体"myEntity"是一个实体的大图,有许多子集合,而这些子集合又有自己的子集合,依此类推.整个图形包含10000个实体的顺序,但通常只更改一小部分.

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

Sla*_*uma 3

恐怕 2.5 秒附加一个包含 10000 个实体的对象图是“正常的”。当您附加图表时,可能会发生实体快照创建,这需要花费这段时间。

如果“通常只更改少量”(例如 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();
}
Run Code Online (Sandbox Code Playgroud)

尽管这将创建大量单个数据库查询,但只会加载没有导航属性的“平面”实体,并且附加(在调用时发生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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

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