web-dev-qa-db-fra.com

Comment dois-je supprimer tous les éléments d'un DbSet?

Quel est le meilleur moyen de supprimer tous les éléments d'un System.Data.Entity.DbSet, avec Entity Framework 4.3?

60
aknuds1
dbContext.Database.ExecuteSqlCommand("delete from MyTable");

(Sans blague.)

Le problème est qu’EF ne prend en charge aucune commande par lot et que le seul moyen de supprimer toutes les entités d’un ensemble sans DML direct serait:

foreach (var entity in dbContext.MyEntities)
    dbContext.MyEntities.Remove(entity);
dbContext.SaveChanges();

Ou peut-être un peu moins cher pour éviter de charger des entités complètes:

foreach (var id in dbContext.MyEntities.Select(e => e.Id))
{
    var entity = new MyEntity { Id = id };
    dbContext.MyEntities.Attach(entity);
    dbContext.MyEntities.Remove(entity);
}
dbContext.SaveChanges();

Mais dans les deux cas, vous devez charger all entités ou all propriétés de clé et supprimer les entités une par une de l'ensemble. De plus, lorsque vous appelez SaveChanges, EF enverra à la base de données n (= nombre d'entités de l'ensemble) DELETE qui seront également exécutées une par une dans la base de données (dans une transaction unique).

Donc, le SQL direct est clairement préférable à cette fin, car vous n'avez besoin que d'une seule instruction DELETE.

89
Slauma

Voici une autre façon de le faire dans le code.

public static class Extensions
{
    public static void DeleteAll<T>(this DbContext context)
        where T : class
    {
        foreach (var p in context.Set<T>())
        {
            context.Entry(p).State = EntityState.Deleted;
        }
    }
}

Pour appeler réellement la méthode et effacer le jeu:

myDbContext.DeleteAll<MyPocoClassName>();
14
Tim Cooke

Ancien post, mais il existe maintenant une méthode RemoveRange:

    dbContext.MyEntities.RemoveRange(dbContext.MyEntities);
    dbContext.SaveChanges();
11
jintux

Si vous souhaitez supprimer tous les éléments sans écrire de code SQL et exécuter uniquement un appel Single Db Call 

Bibliothèque étendue Entity Framework propose une méthode batch delete.

context.Users.Delete();
3
Anestis Kivranoglou

Comme la réponse acceptée ne mentionne que la méthode ci-dessous:

context.Database.ExecuteSqlCommand("delete from MyTable");

et donne plutôt des alternatives à cela, j’ai réussi à écrire une méthode, que vous pouvez utiliser pour éviter de charger toutes les entités, puis les bouclant et utilisant ExecuteSqlCommand à la place.

En supposant que l'on utilise l'unité de travail, où le contexte est DbContext:

using System.Data.Entity.Core.Objects;
using System.Text.RegularExpressions;

public void DeleteAll()
{
    ObjectContext objectContext = ( (IObjectContextAdapter)context ).ObjectContext;
    string sql = objectContext.CreateObjectSet<T>().ToTraceString();
    Regex regex = new Regex( "FROM (?<table>.*) AS" );
    Match match = regex.Match( sql );
    string tableName = match.Groups[ "table" ].Value;

    context.Database.ExecuteSqlCommand( string.Format( "delete from {0}", tableName ) );
}

Le premier bloc de code récupère le nom de la table nécessaire dans ExecuteSqlCommand method.

Usage:

using ( var context = new UnitOfWork() )
{
    context.MyRepository.DeleteAll();
}

Il n'y a pas besoin d'appeler 

context.SaveChanges()
2
Ryfcia

Si vous travaillez avec une unité de travail et un référentiel générique, les éléments suivants peuvent vous être utiles.

public virtual void DeleteWhere(Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;
            if (filter != null)
            {
                query = query.Where(filter);
            }
            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            foreach (var entity in query)
            {
                context.Entry(entity).State = EntityState.Deleted;
            }
        }

Usage:

uow.myRepositoryName.DeleteWhere(u => u.RoomId == roomId);
uow.Save();
1
user2330270

Vous pouvez y arriver en utilisant une requête directe:

 ent.Database.ExecuteSqlCommand("delete from tablename");
0
Ravindra Devrani