Cadre d’entité. Supprimer toutes les lignes du tableau

Comment puis-je supprimer rapidement toutes les lignes de la table en utilisant Entity Framework?

J’utilise actuellement:

var rows = from o in dataDb.Table select o; foreach (var row in rows) { dataDb.Table.Remove(row); } dataDb.SaveChanges(); 

Cependant, l’exécution prend beaucoup de temps.

Y a-t-il des alternatives?

Pour ceux qui sont googler ceci et ont fini ici comme moi, voici comment vous le faites actuellement dans EF5 et EF6:

 context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]"); 

En supposant que le contexte est un System.Data.Entity.DbContext

Attention: Ce qui suit ne convient que pour les petites tables (pensez à <1000 lignes)

Voici une solution qui utilise la structure d’entité (pas SQL) pour supprimer les lignes, ce n’est donc pas spécifique à SQL Engine (R / DBM).

Cela suppose que vous faites cela pour des tests ou une situation similaire. Non plus

  • La quantité de données est petite ou
  • La performance n’a pas d’importance

Appelez simplement:

 VotingContext.Votes.RemoveRange(VotingContext.Votes); 

En supposant ce contexte:

 public class VotingContext : DbContext { public DbSet Votes{get;set;} public DbSet Polls{get;set;} public DbSet Voters{get;set;} public DbSet Candidates{get;set;} } 

Pour un code plus clair, vous pouvez déclarer la méthode d’extension suivante:

 public static class EntityExtensions { public static void Clear(this DbSet dbSet) where T : class { dbSet.RemoveRange(dbSet); } } 

Alors ce qui précède devient:

 VotingContext.Votes.Clear(); VotingContext.Voters.Clear(); VotingContext.Candidacy.Clear(); VotingContext.Polls.Clear(); await VotingTestContext.SaveChangesAsync(); 

J’ai récemment utilisé cette approche pour nettoyer ma firebase database de test pour chaque test (il est évidemment plus rapide que de recréer la firebase database à chaque fois, même si je n’ai pas vérifié la forme des commandes de suppression générées).


Pourquoi peut-il être lent?

  1. EF obtiendra TOUTES les lignes (VotingContext.Votes)
  2. et utilisera ensuite leurs identifiants (pas sûr de savoir comment, peu importe), pour les supprimer.

Donc, si vous travaillez avec une quantité sérieuse de données, vous allez tuer le processus du serveur SQL (il consumra toute la mémoire) et la même chose pour le processus IIS puisque EF mettra en cache toutes les données de la même manière que le serveur SQL. N’utilisez pas celui-ci si votre table contient une quantité sérieuse de données.

L’utilisation de la commande SQL TRUNCATE TABLE sera la plus rapide possible sur la table et non sur les lignes individuelles.

 dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]"); 

En supposant que dataDb est un DbContext (pas un ObjectContext ), vous pouvez l’emballer et utiliser la méthode comme ceci:

 var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext; objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]"); 
 var all = from c in dataDb.Table select c; dataDb.Table.RemoveRange(all); dataDb.SaveChanges(); 
 using (var context = new DataDb()) { var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext; ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name); } 

ou

 using (var context = new DataDb()) { context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]"); } 

Cela évite d’utiliser n’importe quel sql

 using (var context = new MyDbContext()) { var itemsToDelete = context.Set(); context.MyTables.RemoveRange(itemsToDelete); context.SaveChanges(); } 

Je suis tombé sur cette question lorsque je devais traiter un cas particulier: mise à jour complète du contenu dans un tableau “feuille” (pas de FK pointant vers lui). Cela impliquait de supprimer toutes les lignes et de mettre de nouvelles informations sur les lignes et cela devrait être fait de manière transactionnelle (je ne veux pas me retrouver avec une table vide, si les insertions échouent pour une raison quelconque).

J’ai essayé l’approche public static void Clear(this DbSet dbSet) , mais les nouvelles lignes ne sont pas insérées. Un autre inconvénient est que tout le processus est lent, car les lignes sont supprimées une par une.

Donc, je suis passé à l’approche TRUNCATE , car il est beaucoup plus rapide et il est également ROLLBACKable . Il réinitialise également l’identité.

Exemple utilisant le modèle de référentiel:

 public class Repository : IRepository where T : class, new() { private readonly IEfDbContext _context; public void BulkInsert(IEnumerable entities) { _context.BulkInsert(entities); } public void Truncate() { _context.Database.ExecuteSqlCommand($"TRUNCATE TABLE {typeof(T).Name}"); } } // usage DataAccess.TheRepository.Truncate(); var toAddBulk = new List(); // fill toAddBulk from source system // ... DataAccess.TheRepository.BulkInsert(toAddBulk); DataAccess.SaveChanges(); 

Bien sûr, comme déjà mentionné, cette solution ne peut pas être utilisée par les tables référencées par des clés étrangères (TRUNCATE échoue).

si

  using(var db = new MyDbContext()) { await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable");); } 

causes

Impossible de tronquer la table ‘MyTable’ car elle est référencée par une contrainte FOREIGN KEY.

J’utilise ceci:

  using(var db = new MyDbContext()) { await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1"); } 

Si vous souhaitez effacer la totalité de votre firebase database.

En raison des contraintes de clé étrangère, la séquence des tables est importante. C’est un moyen de brutaliser cette séquence.

  public static void ClearDatabase() where T : DbContext, new() { using (var context = new T()) { var tableNames = context.Database.SqlQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%'").ToList(); foreach (var tableName in tableNames) { foreach (var t in tableNames) { try { if (context.Database.ExecuteSqlCommand(ssortingng.Format("TRUNCATE TABLE [{0}]", tableName)) == 1) break; } catch (Exception ex) { } } } context.SaveChanges(); } } 

usage:

 ClearDatabase(); 

N’oubliez pas de réinitialiser votre DbContext après cela.

 var data = (from n in db.users select n); db.users.RemoveRange(data); db.SaveChanges(); 

Cela fonctionne correctement dans EF 5:

 YourEntityModel myEntities = new YourEntityModel(); var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext; objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]"); 

Vous pouvez le faire sans Foreach

 dataDB.Table.RemoveRange(dataDB.Table); dataDB.SaveChanges(); 

Cela supprimera toutes les lignes