2011-05-22 108 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

相關問題