2011-05-22 79 views

回答

45

这将执行很多,比涉及删除各个实体对象的东西多更好,假设底层数据库是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(); 
     } 
    } 

简短说明:

+4

一定要部署和更新数据方面,尽管! – Vinzz 2012-06-12 11:57:09

+3

与TRUNCATE相比,DELETE的一个优点是:对于删除角色db_datawriter就足够了,对于TRUNCATE而言不是!这就是为什么我喜欢DELETE,只要性能足够。需要如下所示的EF5中的 – Tillito 2012-08-23 13:24:15

+4

:context.Database.ExecuteSqlCommand(“TRUNCATE TABLE [”+ tableName +“]”);来自[野兔](http://stackoverflow.com/questions/13857242/where-is-executestorecommand-in-entity-framework-5) – oCcSking 2013-05-20 15:06:47

3

迭代通过与代码像这样的表:

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. 
} 
); 
13

只是懒惰的人,寻找答案时的代码,我想出了自己 我不截断表由于缺乏权限,如果这不是你的问题,随时可以这样做。 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(); 
    } 
+0

再一次修改: 使用反射来查找表名称。 – 2012-11-07 17:08:25

+0

当某个其他程序集中声明了PONO数据类型('Type.GetType'行失败)时,此解决方案将不起作用。否则,好的解决方案! – 2014-05-17 18:18:40

1

截断不能外键内删除。

然后我做了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(); 
    } 
} 
+0

非常好!即使先保存父项并处理上下文,我也无法使用外键来使用TRUNCATE。 – 2015-01-13 12:51:49

2

我想设法改善@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); 
       } 

      } 

     } 

if语句中catch块检查自己是否达到了表列表的最后一个索引,而不删除任何表。在这种情况下,不要进入无限循环,而是抛出异常并退出for。

6

对于EF 6:

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

EF Core仍然是最新的。 – Grimley 2016-08-09 11:43:30

相关问题