删除实体框架中的所有实体

本文关键字:实体 框架 删除 | 更新日期: 2023-09-27 17:57:08

我想使用实体框架 4+ 删除所有表(所有实体)的内容。如何做到这一点?

删除实体框架中的所有实体

假设基础数据库是 MSSQL,这将比涉及删除单个实体对象的任何内容都要好得多

foreach (var tableName in listOfTableNames)
{
    context.ExecuteStoreCommand("TRUNCATE TABLE [" + tableName + "]");
}
当然,如果您的表具有外键

关系,则需要按正确的顺序设置表名称列表,以便在清除外键表可能依赖的任何主键表之前清除外键表。

只是对于懒惰的人,代码 在寻找答案时,我自己想到了:

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();
    }
}

简短解释:由于缺少权限,我不会截断表,如果这对您来说不是问题,请随时这样做。where 语句忽略表__MigrationHistory。

更新:经过一些研究,我想出了更好的解决方案(不是那么好,但只删除必需的列):

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();
}

对于 EF 6:

DbSet<Entity>.RemoveRange(DbSet<Entity>);

使用如下所示的代码遍历表:

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)));

我亲自在实体框架 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。

(In .NetCore)您可以在表上使用RemoveRange,并将表本身作为参数。

Tablename.RemoveRange(Tablename);

断无法删除外键。

然后我为 DbContext 制作了扩展方法。

用法很简单。

.db。Truncates(); 所有表删除。

.db。Truncates("Test1"、"Test2"); 仅删除"测试 1、测试 2"表

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);