如何使用Entity Framework快速删除表中的所有行?
我目前正在使用:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
但是,执行需要很长时间。
还有其他选择吗?
[TableName]
不可移植。
如何使用Entity Framework快速删除表中的所有行?
我目前正在使用:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
但是,执行需要很长时间。
还有其他选择吗?
[TableName]
不可移植。
Answers:
对于那些正在使用谷歌搜索并最终像我这样的人,这是您目前在EF5和EF6中的操作方式:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
假设上下文是一个 System.Data.Entity.DbContext
[
此处的转义特定于SQL Server,但TRUNCATE
命令不是-它是ANSI SQL的一部分,因此可以在大多数SQL方言中使用(尽管不是SQLite)。
警告:以下内容仅适用于小型表(认为<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();
最近,我使用了这种方法来为每个测试用例运行清理我的测试数据库(显然,这比每次从头开始重新创建数据库都快,尽管我没有检查生成的delete命令的形式)。
为什么会变慢?
因此,如果您要处理大量数据,则会杀死SQL Server进程(它将消耗所有内存),并且会破坏IIS进程,因为EF将以与SQL Server相同的方式缓存所有数据。如果您的表中包含大量数据,请不要使用此选项。
使用SQL的TRUNCATE TABLE
命令将是最快的,因为它在表上而不是对单个行进行操作。
dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
假设dataDb
是DbContext
(而不是ObjectContext
),则可以将其包装并使用如下方法:
var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
TRUNCATE TABLE
为DELETE FROM
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
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]");
}
Delete
上IQueryable
-我猜马尼什使用类似EntityFramework.Extended:github.com/loresoft/EntityFramework.Extended
.Delete
是一个自定义扩展名,在首先发布答案的过程中,完全忘了提及此自定义的定义了.Delete
。:)
您无需Foreach就可以做到
dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
这将删除所有行
当我不得不处理一个特殊情况时,我遇到了这个问题:完全更新“叶”表中的内容(没有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失败)。
如果
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");
}
如果您希望清除整个数据库。
由于外键约束,表被截断的顺序很重要。这是暴力破解此序列的一种方法。
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。
以下内容适用于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
重要的一点是,如果在表中使用外键,则必须先删除子表,然后再删除父表,因此删除期间表的顺序(层次结构)很重要,否则可能会发生SQLite异常。
注意:var context = new YourContext()
删除所有记录。不要重置主索引,例如“ truncate”。
/// <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;
}
如果是MVC,则可以执行以下操作:
public async Task<IActionResult> DeleteAll()
{
var list = await _context.YourClass.ToListAsync();
_context.YourClass.RemoveRange(list);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
确保在尝试删除父级时,所有子级在删除时都将级联。或孩子有可为空的外键。
TRUNCATE
担心外键约束。