Что вызывает .Attach () медленно в EF4? - PullRequest
26 голосов
/ 07 мая 2011

У нас есть общий метод обновления в нашем коде, который делает

foreach (var entity in entityList)
{
    Context.GetIDbSet<T>().Attach(entity);
    Context.SetState(entity, EntityState.Modified);
}

Я проверяю это, передавая перечисление сущностей и вызывая его один раз для каждой сущности.

Я обнаружил, что перечисление 1000 сущностей занимает приблизительно 47 с. Это ожидаемое поведение? Или что-то не так с фрагментом кода?

Профилирование показало, что метод Attach () был медленнее, чем метод SetState ().

Тест, на котором я его проводил, был на объекте с 50 свойствами и без отношений, если это как-то повлияет.

1 Ответ

68 голосов
/ 07 мая 2011

Я могу подтвердить это медленное поведение, и я также нашел основную причину.Я провел небольшой тест со следующей моделью ...

public class MyClass
{
    public int Id { get; set; }
    public string P1 { get; set; }
    // ... properties P2 to P49, all of type string
    public string P50 { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<MyClass> MyClassSet { get; set; }
}

... и этой тестовой программой ...

using (var context = new MyContext())
{
    var list = new List<MyClass>();
    for (int i = 0; i < 1000; i++)
    {
        var m = new MyClass()
        {
            Id = i+1,
            P1 = "Some text ....................................",
            // ... initialize P2 to P49, all with the same text
            P50 = "Some text ...................................."
        }
        list.Add(m);
    }

    Stopwatch watch = new Stopwatch();
    watch.Start();
    foreach (var entity in list)
    {
        context.Set<MyClass>().Attach(entity);
        context.Entry(entity).State = System.Data.EntityState.Modified;
    }
    watch.Stop();
    long time = watch.ElapsedMilliseconds;
}

Тест 1

Точно код выше:

-> время = 29,2 сек

Тест 2

Закомментируйте строку ...

//context.Entry(entity).State = System.Data.EntityState.Modified;

-> время = 15,3 с

Тест 3

Закомментируйте строку ...

//context.Set<MyClass>().Attach(entity);

-> время = 57,3 сек

Этот результат очень странный, потому что я ожидал, что вызывать Attach не нужно, потому что изменение состояния все равно происходит.

Тест 4

Удалить свойства P6 - P50 (таким образом, у нас есть только 5 строк в сущности), оригинальный код:

-> time= 3,4 с

Итак, да, очевидно, что количество свойств сильно имеет значение.

Тест 5

Добавьте следующую строку перед циклом (модель снова со всеми 50 свойствами):

context.Configuration.AutoDetectChangesEnabled = false;

-> time =1,4 сек

Тест 6

Опять с AutoDetectChangesEnabled = false, но только с 5 свойствами:

-> время = 1,3 с

Таким образом, без отслеживания изменений количество свойств уже не имеет большого значения.

Заключение

Похоже, что большая часть времени уходит на создание снимка свойств прикрепленного объекта с помощью механизма отслеживания изменений. Если вы нене нужно отключать отслеживание изменений для вашего кода.(Я предполагаю, что в вашем коде вам действительно не нужно отслеживать изменения, потому что, устанавливая состояние полномочий на Modified, вы в основном помечаете все свойства как измененные в любом случае. Так что все столбцы отправляютсяв базу данных в операторе обновления.)

Редактировать

Время тестирования, указанное выше, находится в режиме отладки.Но режим Release не имеет большого значения (например: тест 1 = 28,7 с, тест 5 = 0,9 с).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...