如何删除DbSet中的所有元素?


76

使用Entity Framework 4.3删除System.Data.Entity.DbSet中的所有元素的最佳方法是什么?

Answers:


102
dbContext.Database.ExecuteSqlCommand("delete from MyTable");

(开玩笑。)

问题在于EF不支持任何批处理命令,并且不使用直接DML删除集合中所有实体的唯一方法是:

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

或者也许便宜一点以避免加载完整的实体:

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

但是,在两种情况下,您都必须加载所有实体或所有关键属性,并从集合中一一删除实体。此外,当您调用SaveChangesEF时,它将向数据库发送n个(=集合中的实体数)DELETE语句,这些语句也将在DB中一次(一次交易)被执行。

因此,直接SQL显然是首选,因为您只需要一个DELETE语句。


2
你需要调用SaveChangesdbContext.Database.ExecuteSqlCommand
PeterX

真正的问题是DbContext如何提供对其所有DbSet /实体的访问?除非使用反射,否则无法循环遍历它们。这是您在提及“ MyEntities”时所想到的吗?
Veverke

2
怎么样RemoveRange,而不是Remove?您是否会说“仅在EF 6中引入,而OP询问EF 4. *”?
红豌豆

34

旧帖子,但是现在有一个RemoveRange方法:

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

1
我使用此答案是因为代码简单明了。我敢肯定有更有效的方法来执行此操作,但是我正在与Azure WebJob一起工作,该工作将在一夜之间运行,因此,现在无需担心。
Phil Ringsmuth

RemoveRange的问题在于,您仍然必须从数据库中查询所有实体(至少是ID),因为此方法只是foreach的包装。
Szörényi亚当

18

这是您可以在代码中实现的另一种方法。

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

实际调用方法并清除设置:

myDbContext.DeleteAll<MyPocoClassName>();


2

由于接受的答案仅提及以下方法:

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

并且提供了替代方法,我设法编写了一种方法,您可以使用该方法避免加载所有实体,然后遍历它们并使用ExecuteSqlCommand

假设使用工作单元,其中上下文是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 ) );
}

第一段代码检索ExecuteSqlCommand方法中所需的表名。

用法:

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

没有必要打电话

context.SaveChanges()

1

如果您使用工作单元和通用存储库,则可能会发现以下有用的内容

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

用法:

uow.myRepositoryName.DeleteWhere(u => u.RoomId == roomId);
uow.Save();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.