首页 文章

实体框架 . 删除表中的所有行

提问于
浏览
218

如何使用Entity Framework快速删除表中的所有行?

我目前正在使用:

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

但是,执行需要很长时间 .

还有其他选择吗?

12 回答

  • 173

    对于那些谷歌搜索并最终像我一样的人,这就是你目前在EF5和EF6中的表现:

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

    假设上下文是 System.Data.Entity.DbContext

  • 11

    Warning: 以下内容仅适用于小型表(想想<1000行)

    这是一个使用实体框架(而不是SQL)来删除行的解决方案,因此它不是特定于SQL Engine(R / DBM)的 .

    这假设您正在进行测试或类似情况 . 或

    • 数据量很小或

    • 表现并不重要


    只需致电:

    VotingContext.Votes.RemoveRange(VotingContext.Votes);
    

    假设这个背景:

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

    对于更整洁的代码,您可以声明以下扩展方法:

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

    然后上面变成:

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

    我最近使用这种方法为每个测试用例运行清理我的测试数据库(这显然比每次从头重新创建数据库更快,尽管我没有检查生成的删除命令的形式) .


    Why can it be slow?

    • EF将获取所有行(VotingContext.Votes)

    • 然后将使用他们的ID(不确定具体如何,无关紧要)来删除它们 .

    因此,如果您正在处理大量数据,您将终止SQL服务器进程(它将消耗所有内存)和IIS进程相同的事情,因为EF将以与SQL服务器相同的方式缓存所有数据 . 如果您的表包含大量数据,请不要使用此项 .

  • 28

    使用SQL的TRUNCATE TABLE命令将是最快的,因为它在表上操作而不是在单个行上 .

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

    假设 dataDbDbContext (不是 ObjectContext ),您可以将其包装并使用如下方法:

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

    要么

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

    这可以避免使用任何sql

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

    当我不得不处理一个特定的案例时,我遇到了这个问题:完全更新“叶子”表中的内容(没有指向它的FK) . 这涉及删除所有行并放置新行信息,它应该以事务方式完成(我不希望最终得到一个空表,如果插入因任何原因失败) .

    我尝试了 public static void Clear<T>(this DbSet<T> dbSet) 方法,但没有插入新行 . 另一个缺点是整个过程很慢,因为行被逐个删除 .

    所以,我已经切换到 TRUNCATE 方法,因为它更快,它也是ROLLBACKable . 它也重置了身份 .

    使用存储库模式的示例

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

    当然,如前所述,外键引用的表不能使用此解决方案(TRUNCATE失败) .

  • 3

    如果

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

    原因

    无法截断表'MyTable',因为它是由FOREIGN KEY约束引用的 .

    我用这个:

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

    如果您希望清除整个数据库 .

    由于外键约束,表格被截断的顺序很重要 . 这是一种强制执行此序列的方法 .

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

    用法:

    ClearDatabase<ApplicationDbContext>();
    

    记得在此之后重新实现你的DbContext .

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

    没有Foreach,你可以做到这一点

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

    这将删除所有行

  • 3

    这在EF 5中正常工作:

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

相关问题