我如何才能快速删除使用实体框架表中的所有行?
我目前使用:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
但是,执行起来需要很长时间。
还有其他选择吗?
我如何才能快速删除使用实体框架表中的所有行?
我目前使用:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
但是,执行起来需要很长时间。
还有其他选择吗?
当前回答
我的解决方案,混合了我的想法,一些答案(Ron来自这个帖子,但也有这个和这个反思),并试图涵盖一些不同的条件。
它基于EF6,但它应该工作得很好,只是修复了一些扩展,如GetTableName<TEntity>。
我的解决方案:
使用扩展,所以你只需要DbSet启动 有一个行数阈值,以决定RemoveRange或SQL执行,以避免性能问题 SQL版本基于DELETE而不是TRUNCATE,以避免外键问题(当然,它必须符合您的要求) 有一个参数以内联保存更改
private const int RangeLimit = 100;
private static void ClearTable<TEntity>(this DbSet<TEntity> dataSet, bool saveChanges = true) where TEntity : class
{
DbContext context = null;
if (dataSet.Count() > RangeLimit)
{
context = dataSet.GetContext();
context.Database.ExecuteSqlCommand($"DELETE FROM [{context.GetTableName<TEntity>()}]");
}
else
{
dataSet.RemoveRange(dataSet);
}
if (!saveChanges)
{
return;
}
if (context == null)
{
context = dataSet.GetContext();
}
context.SaveChanges();
}
private static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity : class
{
var internalSet = dbSet
.GetType()
.GetField("_internalSet", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(dbSet);
var internalContext = internalSet?.GetType().BaseType
?.GetField("_internalContext", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(internalSet);
return (DbContext)internalContext?.GetType()
.GetProperty("Owner", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(internalContext, null);
}
public static string GetTableName<TEntity>(this DbContext context) where TEntity : class
{
return (context as IObjectContextAdapter).ObjectContext.CreateObjectSet<TEntity>().EntitySet.Name;
}
对于一个名为Entries的数据库表,你所要做的就是:
databaseContext.Entries.ClearTable();
如果你想保存更改,或者不想保存更改:
databaseContext.Entries.ClearTable(false);
它基于反射,简化代码。当然,它有一些性能上的权衡,但是对于每个表反射一次,因此在这些条件下应该是完全可以接受的。
其他回答
这对我很有用……EF v3.1.5
context.ModelName.RemoveRange(context.ModelName.ToList());
context.SaveChanges();
使用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]");
我的解决方案,混合了我的想法,一些答案(Ron来自这个帖子,但也有这个和这个反思),并试图涵盖一些不同的条件。
它基于EF6,但它应该工作得很好,只是修复了一些扩展,如GetTableName<TEntity>。
我的解决方案:
使用扩展,所以你只需要DbSet启动 有一个行数阈值,以决定RemoveRange或SQL执行,以避免性能问题 SQL版本基于DELETE而不是TRUNCATE,以避免外键问题(当然,它必须符合您的要求) 有一个参数以内联保存更改
private const int RangeLimit = 100;
private static void ClearTable<TEntity>(this DbSet<TEntity> dataSet, bool saveChanges = true) where TEntity : class
{
DbContext context = null;
if (dataSet.Count() > RangeLimit)
{
context = dataSet.GetContext();
context.Database.ExecuteSqlCommand($"DELETE FROM [{context.GetTableName<TEntity>()}]");
}
else
{
dataSet.RemoveRange(dataSet);
}
if (!saveChanges)
{
return;
}
if (context == null)
{
context = dataSet.GetContext();
}
context.SaveChanges();
}
private static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity : class
{
var internalSet = dbSet
.GetType()
.GetField("_internalSet", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(dbSet);
var internalContext = internalSet?.GetType().BaseType
?.GetField("_internalContext", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(internalSet);
return (DbContext)internalContext?.GetType()
.GetProperty("Owner", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(internalContext, null);
}
public static string GetTableName<TEntity>(this DbContext context) where TEntity : class
{
return (context as IObjectContextAdapter).ObjectContext.CreateObjectSet<TEntity>().EntitySet.Name;
}
对于一个名为Entries的数据库表,你所要做的就是:
databaseContext.Entries.ClearTable();
如果你想保存更改,或者不想保存更改:
databaseContext.Entries.ClearTable(false);
它基于反射,简化代码。当然,它有一些性能上的权衡,但是对于每个表反射一次,因此在这些条件下应该是完全可以接受的。
这里有几个问题,几乎所有的答案:
1]硬编码的sql。括号是否适用于所有数据库引擎? 2]实体框架Remove和RemoveRange调用。这会将所有实体加载到受操作影响的内存中。呵。 3]截表。与外键引用中断,可能无法跨所有数据库引擎工作。
使用https://entityframework-plus.net/,他们处理跨数据库平台的事情,将删除转换为正确的sql语句,并且不将实体加载到内存中,并且该库是免费的开源的。
免责声明:我不隶属于nuget包。他们确实提供了付费版本,功能甚至更多。
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();