Hoe wis ik een grote persistente verzameling snel?

Ik heb een entiteit Foo met een verzameling Bars .

Deze verzameling is vrij groot (zeg 20.000 elementen, en ja, deze moet volledig worden geladen, omdat deze wordt weergegeven in een TreeView) en de elementen worden automatisch gegenereerd op basis van enkele parameters van de Foo die de gebruiker kan veranderen, met behulp van een wpf MVVM-applicatie (alle verwerking vindt plaats in de client)

Nadat hij tevreden is met de resultaten, slaat hij op opslaan en wordt DbContext.SaveChanges() aangeroepen.

Generating Bars implies clearing the collection, then doing a bunch of calculations and adding the new elements. When this is a new, non-persistent Foo, it's no problem because I can just call foo.Bars.Clear()

Het probleem is, dat doen met al bestaande entiteiten ervoor zorgt dat EF bar.Foo = null in alle elementen instelt, in plaats van ze te verwijderen.

Mijn oplossing gaat als volgt:

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

The problem with this solution is that it doesn't scale. Calling Entry(bar).State = EntityState.Detached when there are many entities loaded is even slower than just calling context.Set().Remove(bar) and letting EF do the deletes one by one, so it defeats the purpose of the workaround.

So, my question is: Is there any efficient way to make EF believe the collection is actually empty?

Of moet ik het op een geheel andere manier doen?

1

1 antwoord

Nou, het was makkelijker dan ik dacht.

Ik heb deze regel vervangen:

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

met deze (waarvan ik dacht dat die min of meer equivalent was):

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

En het is nu binnen een redelijke tijd voltooid.

1
toegevoegd