Entity Framework. Delete all rows in table
如何使用Entity Framework快速删除表中的所有行?
我目前正在使用:
1 2 3 4 5 6 7 | var rows = from o in dataDb.Table select o; foreach (var row in rows) { dataDb.Table.Remove(row); } dataDb.SaveChanges(); |
但是,执行需要很长时间。
还有其他选择吗?
对于那些谷歌搜索并最终像我一样的人,这就是你目前在EF5和EF6中的表现:
1 | context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]"); |
假设上下文是
警告:以下内容仅适用于小型表(想想<1000行)
这是一个使用实体框架(而不是SQL)来删除行的解决方案,因此它不是特定于SQL Engine(R / DBM)的。
这假设您正在进行测试或类似情况。
或
- 数据量很小或
- 表现无关紧要
只需致电:
1 | VotingContext.Votes.RemoveRange(VotingContext.Votes); |
假设这个背景:
1 2 3 4 5 6 7 | 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;} } |
对于更整洁的代码,您可以声明以下扩展方法:
1 2 3 4 5 6 7 | public static class EntityExtensions { public static void Clear< T >(this DbSet< T > dbSet) where T : class { dbSet.RemoveRange(dbSet); } } |
然后上面变成:
1 2 3 4 5 | VotingContext.Votes.Clear(); VotingContext.Voters.Clear(); VotingContext.Candidacy.Clear(); VotingContext.Polls.Clear(); await VotingTestContext.SaveChangesAsync(); |
我最近使用这种方法为每个测试用例运行清理我的测试数据库(这显然比每次从头重新创建数据库更快,尽管我没有检查生成的删除命令的形式)。
为什么它会慢?
因此,如果您正在处理大量数据,那么您将终止SQL服务器进程(它将消耗所有内存)和IIS进程同样的事情,因为EF将以与SQL服务器相同的方式缓存所有数据。如果您的表包含大量数据,请不要使用此项。
使用SQL的
1 | dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]"); |
假设
1 2 | var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext; objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]"); |
1 2 3 | var all = from c in dataDb.Table select c; dataDb.Table.RemoveRange(all); dataDb.SaveChanges(); |
1 2 3 4 5 | using (var context = new DataDb()) { var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext; ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name); } |
要么
1 2 3 4 | using (var context = new DataDb()) { context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]"); } |
这可以避免使用任何sql
1 2 3 4 5 6 | using (var context = new MyDbContext()) { var itemsToDelete = context.Set<MyTable>(); context.MyTables.RemoveRange(itemsToDelete); context.SaveChanges(); } |
没有Foreach,你可以做到这一点
1 2 | dataDB.Table.RemoveRange(dataDB.Table); dataDB.SaveChanges(); |
这将删除所有行
当我不得不处理一个特定的案例时,我遇到了这个问题:完全更新"叶子"表中的内容(没有指向它的FK)。这涉及删除所有行并放置新行信息,它应该以事务方式完成(我不希望最终得到一个空表,如果插入因任何原因失败)。
我尝试了
所以,我已经切换到
使用存储库模式的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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失败)不能使用此解决方案。
如果您希望清除整个数据库。
由于外键约束,表格被截断的顺序很重要。这是一种强制执行此序列的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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(); } } |
用法:
1 | ClearDatabase<ApplicationDbContext>(); |
记得在此之后重新实现你的DbContext。
如果
1 2 3 4 | using(var db = new MyDbContext()) { await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable");); } |
原因
无法截断表'MyTable',因为它正被FOREIGN KEY约束引用。
我用这个:
1 2 3 4 | using(var db = new MyDbContext()) { await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1"); } |
1 2 3 | var data = (from n in db.users select n); db.users.RemoveRange(data); db.SaveChanges(); |
这在EF 5中正常工作:
1 2 3 4 | YourEntityModel myEntities = new YourEntityModel(); var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext; objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]"); |
删除所有记录。不要像"truncate"那样重置主索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /// <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; } |