7

我正在使用 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 秒,所以我想知道这是否可以改进。我看过一些文章告诉你 set AutoDetectChangesEnabled = false,我在上面做的,但这对我的场景没有任何影响。为什么是这样?

4

1 回答 1

3

恐怕用 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);
        }
    }

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

于 2013-05-01T11:58:26.033 回答