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

Zhe*_*nia 261 c# sql linq entity-framework

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

我目前正在使用:

var rows = from o in dataDb.Table
           select o;
foreach (var row in rows)
{
    dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

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

还有其他选择吗?

Ron*_*ijm 281

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

context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
Run Code Online (Sandbox Code Playgroud)

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

  • 仅供参考,为了使用TRUNCATE,用户必须对表具有ALTER权限.(http://stackoverflow.com/questions/4735038/permissions-for-truncating-a-table) (16认同)
  • @Alex浪费了大量时间在错误"无法找到对象MyTable,因为它不存在或您没有权限." 出于这个确切的原因 - 很少授予EF应用程序ALTER权限,并且错误消息确实会让您进行疯狂的追逐. (7认同)
  • 我有问题,因为我的表是外键关系的一部分,即使它是该关系中的叶表.我使用了context.Database.ExecuteSqlCommand("DELETE FROM [Interests]"); 代替 (7认同)
  • 请注意,虽然此处的 `[` 转义特定于 SQL Server,但 `TRUNCATE` 命令不是 - 它是 ANSI SQL 的一部分,因此可以在大多数 SQL 方言中使用(尽管不是 SQLite)。 (2认同)

Ahm*_*ejo 196

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

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

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

  • 数据量很小
  • 表现无关紧要

只需致电:

VotingContext.Votes.RemoveRange(VotingContext.Votes);
Run Code Online (Sandbox Code Playgroud)

假设这个背景:

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;}
}
Run Code Online (Sandbox Code Playgroud)

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

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

然后上面变成:

VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();
Run Code Online (Sandbox Code Playgroud)

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


为什么它会慢?

  1. EF将获得所有行(VotingContext.Votes)
  2. 然后将使用他们的ID(不确定具体如何,无关紧要)来删除它们.

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

  • 这不会重置身份密钥。因此,如果您清除10条记录,则下一条仍为11条。 (2认同)

Rud*_*ser 87

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

dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
Run Code Online (Sandbox Code Playgroud)

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

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
Run Code Online (Sandbox Code Playgroud)

  • 但 DELETE 不会重置 IDENTITY 种子。在某些情况下这可能会出现问题。 (3认同)
  • 如果尝试此操作时遇到权限错误,只需将“TRUNCATE TABLE”更改为“DELETE FROM” (2认同)
  • @codeMonkey 请注意,这些是不同的操作,但会产生(几乎)相同的净效果 (2认同)

小智 39

var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

  • 这不应该被使用,因为您执行完全选择和删除后而不是仅删除.从时间性能来看,这是一个很大的不! (9认同)
  • 即使它很少被称为这是坏事.由于EF更改跟踪的速度有限,因此仅包含3000个条目的表格可能需要超过30秒. (4认同)
  • @HellBaby除非它很少被调用,因此性能完全无关紧要. (2认同)
  • 非常适合我的单元测试中的内存数据库:) (2认同)

Man*_*hra 36

using (var context = new DataDb())
{
     var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
     ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}
Run Code Online (Sandbox Code Playgroud)

要么

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


Bob*_*lth 23

EF Core 7.0通过添加批量更新和删除语义一劳永逸地解决了这个问题:

await dataDB.Table.ExecuteDeleteAsync();
Run Code Online (Sandbox Code Playgroud)

请注意,此语法立即执行基础 (SQL) 命令以从表中删除数据。它不会花时间跟踪实体、将其标记为删除以及等待UpdateDatabase对数据库执行事务。

另请注意,默认情况下,多个ExecuteDeleteExecuteUpdate命令不会包含在单个事务中。但是,可以按照正常方式使用 DbContext 事务 API 将这些命令包装在事务中。

  • 这应该是这个问题的首选答案,自定义 SQL *不能*跨不同的数据库引擎工作。 (3认同)

Rob*_*ick 16

这可以避免使用任何sql

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)


Omi*_*vid 14

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

dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

这将删除所有行

  • 仅适用于小桌子 (4认同)

Ale*_*xei 9

当我不得不处理一个特定的案例时,我遇到了这个问题:完全更新"叶子"表中的内容(没有指向它的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();
Run Code Online (Sandbox Code Playgroud)

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


sul*_*ifi 7

context.TableName.RemoveRange(context.TableName);
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)


Zak*_*kos 5

如果

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

原因

无法截断表“ MyTable”,因为它已被FOREIGN KEY约束引用。

我用这个:

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


小智 5

var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)


Mat*_*len 5

以下适用于 SQLite 数据库(使用实体框架)。

似乎清除所有数据库表的最快方法是使用context.Database.ExecuteSqlCommand("some SQL"),正如上面的一些评论也突出显示的那样。在这里我将展示如何重置表的“索引”计数。

context.Database.ExecuteSqlCommand("delete from TableA");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableA'");//resets the autoindex

context.Database.ExecuteSqlCommand("delete from TableB");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableB'");//resets the autoindex 

context.Database.ExecuteSqlCommand("delete from TableC");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableC'");//resets the autoindex 
Run Code Online (Sandbox Code Playgroud)

重要的一点是,如果在表中使用外键,则必须先删除子表,再删除父表,因此删除时表的顺序(层次结构)很重要,否则可能会出现 SQLite 异常。

笔记:var context = new YourContext()