web-dev-qa-db-fra.com

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

Comment puis-je supprimer rapidement toutes les lignes d'un tableau à l'aide d'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?

249
Zhenia

Pour ceux qui googuent cela et se sont retrouvés 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

272
Ron Sijm

Avertissement: Ce qui suit ne convient que pour les petites tables (pensez à moins de 1000 lignes)

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

Cela suppose que vous le faites pour des tests ou une situation similaire. Soit

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

Appelez simplement:

VotingContext.Votes.RemoveRange(VotingContext.Votes);

En supposant que ce contexte:

public class VotingContext : DbContext
{
    public DbSet<Vote> Votes{get;set;}
    public DbSet<Poll> Polls{get;set;}
    public DbSet<Voter> Voters{get;set;}
    public DbSet<Candidacy> Candidates{get;set;}
}

Pour le code plus ordonné, vous pouvez déclarer la méthode d'extension suivante:

public static class EntityExtensions
{
    public static void Clear<T>(this DbSet<T> 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 base de données de test pour chaque exécution de test (c'est évidemment plus rapide que de recréer la base de données à partir de zéro à chaque fois, bien que je n'ai pas vérifié le formulaire des commandes de suppression générées).


Pourquoi cela peut-il être lent?

  1. EF obtiendra TOUTES les lignes (VotingContext.Votes)
  2. et utilisera ensuite leurs identifiants (ne sachant pas exactement comment, peu importe), pour les supprimer.

Donc, si vous travaillez avec une quantité importante de données, le processus du serveur SQL sera tué (il consommera toute la mémoire). Même chose pour le processus IIS, puisque EF mettra en cache toutes les données de la même manière que Serveur SQL. N'utilisez pas celui-ci si votre table contient une quantité importante de données.

191
Ahmed Alejo

L'utilisation de la commande TRUNCATE TABLE de SQL est la plus rapide car elle opère sur la table et non sur des lignes individuelles.

_dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
_

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

_var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
_
84
Rudi Visser
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
37
user3328890
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]");
}
33
Manish Mishra

Cela évite d'utiliser n'importe quel sql

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}
14
Rob Sedgwick

Vous pouvez le faire sans Foreach

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

Cela supprimera toutes les lignes

12
Omid Farvid

Je suis tombé sur cette question lorsque j'ai dû traiter un cas particulier: la mise à jour complète du contenu dans un tableau "feuille" (aucun FK ne le pointe). Cela impliquait de supprimer toutes les lignes et de mettre de nouvelles informations sur les lignes, et cela devrait se faire 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<T>(this DbSet<T> dbSet), mais les nouvelles lignes ne sont pas insérées. Un autre inconvénient est que l'ensemble du processus est lent, car les lignes sont supprimées une par une.

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

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

public class Repository<T> : IRepository<T> where T : class, new()
{
    private readonly IEfDbContext _context;

    public void BulkInsert(IEnumerable<T> entities)
    {
        _context.BulkInsert(entities);
    }

    public void Truncate()
    {
        _context.Database.ExecuteSqlCommand($"TRUNCATE TABLE {typeof(T).Name}");
    }
 }

 // usage 
 DataAccess.TheRepository.Truncate();
 var toAddBulk = new List<EnvironmentXImportingSystem>();

 // fill toAddBulk from source system
 // ...

 DataAccess.TheRepository.BulkInsert(toAddBulk);
 DataAccess.SaveChanges();

Bien entendu, 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).

9
Alexei

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");
               }
4
Zakos

Si vous souhaitez effacer toute votre base de données.

En raison des contraintes de clé étrangère, l'ordre dans lequel les tables sont tronquées importe. C'est un moyen de forcer brutalement cette séquence.

    public static void ClearDatabase<T>() where T : DbContext, new()
    {
        using (var context = new T())
        {
            var tableNames = context.Database.SqlQuery<string>("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(string.Format("TRUNCATE TABLE [{0}]", tableName)) == 1)
                            break;

                    }
                    catch (Exception ex)
                    {

                    }
                }
            }

            context.SaveChanges();
        }
    }

usage:

ClearDatabase<ApplicationDbContext>();

n'oubliez pas de rétablir votre DbContext après cela.

4
Kristian Nissen
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
4
DBB

Cela fonctionne correctement dans EF 5:

YourEntityModel myEntities = new YourEntityModel();

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

Supprimer tous les enregistrements. Ne réinitialisez pas l'index primaire comme "tronquer".

/// <summary>
/// SET - DELETE all record by table - no truncate - return deleted records
/// </summary>
public static int setListDelAllMYTABLE()
{
    // INIT
    int retObj = 0;
    using (MYDBEntities ctx = new MYDBEntities())
    {
        // GET - all record
        var tempAllRecord = ctx.MYTABLE.ToList();
        // RESET
        ctx.MYTABLE.RemoveRange(tempAllRecord);
        // SET - final save
        retObj += ctx.SaveChanges();
    }
    // RET
    return retObj;
}
0
Roberto Mutti