Come posso eliminare 1.000 righe con EF6?

Sto usando Entity Framework 6.

Ho una tabella con le informazioni sul test chiamato Test. Sto eliminando le righe da questa tabella prima ottenendo un elenco dei test, eseguendo un’eliminazione per ciascuno e quindi un commit.

var testList = _testService.GetTests(1, userId).ToList(); testList.ForEach(_obj => _uow.Tests.Delete(_obj)); _uow.Commit(); 

Ho un’altra tabella con le informazioni sulle domande chiamate Domande. Mi piacerebbe fare lo stesso, ma ci sono oltre 1000 righe in questa tabella. Se li elenco tutti e quindi fare 1000 eliminazioni questo non sarà molto efficiente.

Questa cancellazione di domande non avviene molto spesso. Qualcuno ha un suggerimento su come potrei fare questo. Dovrei fare 1000 eliminazioni. È normale fare questo genere di cose usando EF?

    EF 6, per quanto ne so, ha introdotto l’opzione .RemoveRange () sul tuo DbContext. Quindi, in breve, puoi fare qualcosa di simile al seguente:

     var db = new MyDbContext(); var itemsToDelete = db.MyTable.Where(x=>!x.active); db.MyTable.RemoveRange(itemsToDelete); db.SaveChanges(); 

    Quindi, invece di dover fare qualsiasi tipo di foreach , puoi utilizzare questo nuovo metodo di estensione. Con il contesto della tua Unità di lavoro, potresti avere un sovraccarico del tuo metodo Delete che accetta un object IEnumerable (? *) Invece di un singolo object Test come il tuo metodo corrente. Questo nuovo overload dovrebbe richiamare la funzione RemoveRange() sul DbContext.

    ? * – Dipende da cosa GetTests() , ma penso che IEnumerable<> copra sia un IList<> che un IQueryable<>

    modificare

    Un paio di commenti Per prima cosa, non chiamerei .ToList() prima di rilasciare RemoveRange perché non vuoi recuperare effettivamente gli articoli al tuo servizio. Questo dovrebbe aiutare a ridurre alcuni tempi di esecuzione. In secondo luogo, hai ragione, tipo, che emetterete ancora 1000 istruzioni di cancellazione. Tuttavia, i vantaggi in termini di prestazioni derivano dal non chiamare ChangeTracker in EF per ogni singolo elemento che si sta rimuovendo da DbSet . Dalla rivista MSDN :

    AddRange e RemoveRange Come accennato in precedenza, AddRange e RemoveRange sono contributi del membro della comunità Zorrilla. Ogni metodo prende come parametro un numero enumerabile di un singolo tipo di quadro. Nel primo esempio di codice nella sezione DbTransactions di condivisione, ho utilizzato AddRange quando ho passato in una matrice di istanze di Casino:

    context.Casinos.AddRange (new [] {casino1, casino2}); Questi metodi vengono eseguiti molto più velocemente rispetto all’aggiunta o alla rimozione di un singolo object alla volta poiché, per impostazione predefinita, Entity Framework chiama DetectChanges in ciascun metodo Aggiungi e Rimuovi. Con i metodi Range, puoi gestire più oggetti mentre DetectChanges viene chiamato una sola volta, migliorando notevolmente le prestazioni. L’ho provato usando cinque, 50, 500, 5.000 e persino 50.000 oggetti e, almeno nel mio scenario, non c’è limite alla dimensione dell’array, ed è incredibilmente veloce! Tieni presente che questo miglioramento è rilevante solo per far agire il contesto sugli oggetti e non ha alcun effetto su SaveChanges. La chiamata a SaveChanges esegue ancora un solo comando di database alla volta. Quindi, mentre puoi aggiungere rapidamente 50.000 oggetti in un contesto, riceverai comunque 50.000 comandi di inserimento eseguiti singolarmente quando chiami SaveChanges, probabilmente non qualcosa che vuoi fare in un sistema reale.

    D’altra parte, ci sono state lunghe discussioni sull’implementazione del supporto per le operazioni di massa senza richiedere che gli oggetti vengano tracciati da EF (bit.ly/16tMHw4), e per le operazioni batch per consentire l’invio di più comandi insieme in una singola chiamata al database (bit.ly/PegT17). Nessuna delle due funzionalità è entrata nella versione iniziale di EF6, ma entrambe sono importanti e previste per una futura versione.

    Se si desidera solo emettere un singolo comando di database, una procedura memorizzata di utilizzo di istruzioni SQL non elaborate sarebbe la strada da percorrere poiché EntityFramework non supporta le transazioni di massa. Tuttavia, utilizzando gli elementi RemoveRange e AddRange (specialmente se, come hai detto, non sono frequenti) risparmierai molto tempo rispetto a chiamare Remove() in un ciclo foreach.

    Costruito nel sistema Entity Framework .RemoveRange () , continua a scansionare le voci in memoria, ed emette X cancella il ciclo nonostante tutte.

    Se non si desidera scrivere Any SQL per l’eliminazione, in particolare quando si selezionano le quadro da eliminare complessa

    La libreria Entity Framework Plus offre metodi batch delete-update che emettono solo un singolo comando.

     // Deleting context.Users .Where(u => u.FirstName == "firstname") .Delete(); 

    Una limitazione attuale di Entity Framework è che per aggiornare o eliminare un’ quadro è necessario prima recuperarla in memoria. Ora nella maggior parte degli scenari questo va bene. Ci sono tuttavia alcuni senesi in cui le prestazioni ne risentirebbero. Inoltre, per le eliminazioni singole, l’object deve essere recuperato prima che possa essere eliminato richiedendo due chiamate al database. L’aggiornamento e l’eliminazione in gruppo elimina la necessità di recuperare e caricare un’entity framework prima di modificarla.

    Ho effettuato alcuni test utilizzando EF6 e Sql Server Profiler

    Utilizzando .RemoveRange ()

    Prima recupera tutti i record da cancellare dal database

    exec sp_executesql N’SELECT [Extent1]. [Id] AS [Id], [Extent1]. [IdOrder] AS [IdOrder], [Extent1]. [Nome] AS [Nome], [Estensione1]. [Partita] AS [ Partita], FROM [dbo]. [MyTable] AS [Extent1] WHERE [Extent1]. [IdOrder] = @ p__linq__0 ‘, N’ @ p__linq__0 varchar (8000) ‘, @ p__linq__0 =’ 0cb41f32-7ccb-426a-a159- b85a4ff64c29′

    Quindi spara N cancella il comando nel database

    exec sp_executesql N’DELETE [dbo]. [MyTable] WHERE ([Id] = @ 0) ‘, N’ @ 0 varchar (50) ‘, @ 0 =’ ffea29aa-8ba5-4ac9-871b-3f5979180006 ‘

    X 1000 volte

    Questo succede anche usando e IQueryble

    Utilizzando la libreria estesa di Entity Framework

    Spara un solo comando al database

    exec sp_executesql N’DELETE [dbo]. [MyTable] FROM [dbo]. [MyTable] AS j0 INNER JOIN (SELEZIONA 1 AS [C1], [Extent1]. [Id] AS [Id] FROM [dbo]. [MyTable ] AS [Extent1] WHERE [Extent1]. [IdOrder] = @ p__linq__0) AS j1 ON (j0. [Id] = j1. [Id]) ‘, N’ @ p__linq__0 nvarchar (36) ‘, @ p__linq__0 = N’ 0cb41f32-7ccb-426a-A159-b85a4ff64c29′