【发布时间】:2011-08-30 16:06:03
【问题描述】:
我想使用 Entity Framework 4+ 删除所有表(所有实体)的内容。如何做到这一点?
【问题讨论】:
标签: c# .net wpf entity-framework
我想使用 Entity Framework 4+ 删除所有表(所有实体)的内容。如何做到这一点?
【问题讨论】:
标签: c# .net wpf entity-framework
假设底层数据库是 MSSQL,这将比涉及删除单个实体对象的任何操作要好得多,很多。
foreach (var tableName in listOfTableNames)
{
context.ExecuteStoreCommand("TRUNCATE TABLE [" + tableName + "]");
}
当然,如果您的表有外键关系,您需要按正确的顺序设置表名列表,以便在清除任何主键表之前先清除外键表取决于。
【讨论】:
TRUNCATE 不是事务性的!这就是为什么它很快。如果出现问题,您将遇到麻烦。
仅供懒人参考,代码是我自己在寻找答案时想出来的:
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)
{
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableName));
}
context.SaveChanges();
}
}
简短说明: 由于缺少权限,我不会截断表,如果这对您来说不是问题,请随意这样做。 __MigrationHistory 表被 where 语句忽略。
更新:经过一些研究,我想出了更好的解决方案(不是很好,但只删除了必需的列):
public static void ClearDatabase(DbContext context)
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var entities = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace).BaseEntitySets;
var method = objectContext.GetType().GetMethods().First(x => x.Name == "CreateObjectSet");
var objectSets = entities.Select(x => method.MakeGenericMethod(Type.GetType(x.ElementType.FullName))).Select(x => x.Invoke(objectContext, null));
var tableNames = objectSets.Select(objectSet => (objectSet.GetType().GetProperty("EntitySet").GetValue(objectSet, null) as EntitySet).Name).ToList();
foreach (var tableName in tableNames)
{
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableName));
}
context.SaveChanges();
}
【讨论】:
Type.GetType 行失败),此解决方案将不起作用。否则,很好的解决方案!
对于 EF 6:
DbSet<Entity>.RemoveRange(DbSet<Entity>);
【讨论】:
DbSet 与您的DbContext 没有关联。尝试使用谷歌搜索,因为您的错误与此答案无关
DbSet 中删除所有内容。如果您对“当前上下文中不存在名称 'DbSetExample'”有疑问,并且在 Internet 上找不到答案,或者您可以随时提出问题。你永远不知道它可能会帮助其他人:-)
使用类似这样的代码遍历表:
context.GetType().GetProperties()
.Where(propertyInfo => propertyInfo.PropertyType == typeof(Table<>))
.Select(propertyInfo => propertyInfo.GetValue(context, null) as ITable).ToList()
.Foreach(table =>
{
//code that deletes the actual tables records.
}
);
【讨论】:
我想尝试改进@Wojciech Markowski 的出色回答。
如果你像我一样懒惰并且不想检查外键约束, 你可以使用这个方法:
private void ClearDatabase(TContext context)
{
// disable all foreign keys
//context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%'").ToList();
for (int i = 0; tableNames.Count>0; i++)
{
try
{
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
tableNames.RemoveAt(i % tableNames.Count);
i = 0;
}
catch { } // ignore errors as these are expected due to linked foreign key data
}
context.SaveChanges();
}
ClearDatabase 方法遍历表列表并清理它们。如果找到 FK 约束,则捕获异常并转到下一个表。 最后所有表都将被删除。
此外,如果您不介意放松所有 FK 约束,您可以通过以下行禁用所有这些约束:
context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
还有一点: 如果要删除所有表而不只是清除它们,请替换以下行:
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
与:
context.Database.ExecuteSqlCommand(string.Format("DROP TABLE {0}", tableNames.ElementAt(i % tableNames.Count)));
我亲自在 Entity Framework 6 上通过代码优先迁移检查了这个答案。
编辑:更好的版本:
private void ClearDatabase(MrSaleDbContext context)
{
//Optional: disable all foreign keys (db-schema will be loosed).
//context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%' AND TABLE_NAME NOT LIKE 'AspNet%'").ToList();
for (int i = 0; tableNames.Count > 0; i++)
{
try
{
//To delete all tables and not just clean them from data, replace "DELETE FROM {0}" in "DROP TABLE {0}":
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
tableNames.RemoveAt(i % tableNames.Count);
i = -1; //flag: a table was removed. in the next iteration i++ will be the 0 index.
}
catch (System.Data.SqlClient.SqlException e) // ignore errors as these are expected due to linked foreign key data
{
if ((i % tableNames.Count) == (tableNames.Count - 1))
{
//end of tables-list without any success to delete any table, then exit with exception:
throw new System.Data.DataException("Unable to clear all relevant tables in database (foriegn key constraint ?). See inner-exception for more details.", e);
}
}
}
catch 块中的 if 语句检查我是否在不删除任何表的情况下到达表列表的最后一个索引。在这种情况下,不要进入无限循环,而是抛出异常并退出 for。
【讨论】:
(在 .NetCore 中)您可以在表格上使用 RemoveRange 并将表格本身作为参数。
Tablename.RemoveRange(Tablename);
【讨论】:
truncate 无法在外键中删除。
然后我为 DbContext 做了扩展方法。
用法很简单。
db.Truncates(); // 删除所有表。
db.Truncates("Test1", "Test2"); // 只删除“Test1,Test2”表
public static class DbContextExtension
{
public static int Truncates(this DbContext db, params string[] tables)
{
List<string> target = new List<string>();
int result = 0;
if (tables == null || tables.Length == 0)
{
target = db.GetTableList();
}
else
{
target.AddRange(tables);
}
using (TransactionScope scope = new TransactionScope())
{
foreach (var table in target)
{
result += db.Database.ExecuteSqlCommand(string.Format("DELETE FROM [{0}]", table));
db.Database.ExecuteSqlCommand(string.Format("DBCC CHECKIDENT ([{0}], RESEED, 0)", table));
}
scope.Complete();
}
return result;
}
public static List<string> GetTableList(this DbContext db)
{
var type = db.GetType();
return db.GetType().GetProperties()
.Where(x => x.PropertyType.Name == "DbSet`1")
.Select(x => x.Name).ToList();
}
}
【讨论】:
这对我有用... EF v3.1.5
context.ModelName.RemoveRange(context.ModelName.ToList());
context.SaveChanges();
【讨论】:
我想贡献我的一份力量。
我想出了这个查询,它完全符合作者的要求。这是 .NET 5。
var query = "sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL; SET QUOTED_IDENTIFIER ON; DELETE FROM ?; ALTER TABLE ? CHECK CONSTRAINT ALL;'"
context.Database.ExecuteSqlRaw(query);
【讨论】: