Как мне быстро очистить большую постоянную коллекцию?

#entity-framework-4.1

#entity-framework-4.1

Вопрос:

У меня есть объект Foo с Bars коллекцией.

Эта коллекция довольно большая (скажем, 20 000 элементов, и да, ее нужно загрузить полностью, потому что она отображается в виде дерева), и элементы генерируются автоматически на основе некоторых параметров Foo , которые пользователь может изменить, используя приложение WPF MVVM (вся обработка происходит в клиенте)

После того, как он удовлетворен результатами, он нажимает сохранить и DbContext.SaveChanges() вызывается.

Генерация Bars подразумевает очистку коллекции, затем выполнение множества вычислений и добавление новых элементов. Когда это новое, непостоянное Foo , это не проблема, потому что я могу просто позвонить foo.Bars.Clear()

Проблема в том, что выполнение этого с уже постоянными объектами приводит к тому, что EF устанавливается bar.Foo = null во всех элементах вместо их удаления.

Мой обходной путь выглядит следующим образом:

 void Regenerate()
{    
    if (fooIsPersistent)
    {
        foreach (var bar in foo.Bars.ToList())
            context.Entry(bar).State = EntityState.Detached;
        deleteOnSave = true;
    }
    else
        foo.Bars.Clear();
    AddTheNewCalculatedElements()
}

void Save()
{
    if (deleteOnSave)
        context.Database.ExecuteSqlCommand("delete Bar where Foo = @Id", param);
    context.SaveChanges();
}
 

Проблема с этим решением заключается в том, что оно не масштабируется. Вызов Entry(bar).State = EntityState.Detached , когда загружено много объектов, выполняется даже медленнее, чем просто вызов context.Set<Bar>().Remove(bar) и разрешение EF выполнять удаления один за другим, поэтому он сводит на нет цель обходного пути.

Итак, мой вопрос таков: есть ли какой-нибудь эффективный способ заставить EF поверить, что коллекция на самом деле пуста?

Или я должен сделать это совершенно по-другому?

Ответ №1:

Что ж, это было проще, чем я думал.

Я заменил эту строку:

 context.Entry(bar).State = EntityState.Detached;
 

с этим (который, как мне казалось, был более или менее эквивалентен):

 ((IObjectContextAdapter)context).ObjectContext.Detach(bar);
 

И теперь он завершается в разумные сроки.