2011-05-22 28 views

Respuesta

45

Esto realizará mucho, mucho mejor que cualquier cosa que implica la supresión de objetos de entidad individuales, suponiendo que la base de datos subyacente es MSSQL.

foreach (var tableName in listOfTableNames) 
{ 
    context.ExecuteStoreCommand("TRUNCATE TABLE [" + tableName + "]"); 
} 

Por supuesto, si las tablas tienen relaciones de clave externa, que necesitará para configurar la lista de nombres de tabla en el orden correcto para que clara tablas de clave externa antes de borrar cualquier-clave primaria tablas de las que podrían depender.

+4

Asegúrese de desechar y renovar su contexto de datos, sin embargo! – Vinzz

+3

Una ventaja de DELETE en comparación con TRUNCATE: para ELIMINAR el rol db_datawriter es suficiente, ¡para TRUNCATE no lo es! Es por eso que prefiero ELIMINAR siempre que el rendimiento sea suficiente. – Tillito

+4

en EF5 que necesitan ser así: context.Database.ExecuteSqlCommand ("TRUNCATE TABLE [" + tableName + "]"); que vino de [liere] (http://stackoverflow.com/questions/13857242/where-is-executestorecommand-in-entity-framework-5) – oCcSking

3

Iterar a través de las mesas con un código de algo como esto:

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

Solo para los perezosos, código que se acercó a mí mismo en la búsqueda de la respuesta:

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

Breve explicación: yo no truncar tablas debido a la falta de permisos, si no es un problema para usted, siéntete libre de hacerlo. La tabla __MigrationHistory es ignorada por la instrucción where.

ACTUALIZACIÓN: Después de algunas investigaciones que se me ocurrió mejor solución (no tan agradable, pero sólo elimina columnas requeridas):

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

Una modificación más: use la función de reflexión para buscar los nombres de las tablas. –

+0

Esta solución no funcionará cuando el tipo de datos PONO se declare en algún otro ensamblaje (la línea 'Type.GetType' falla). De lo contrario, buena solución! –

1

truncado no pudo eliminar dentro de clave externa.

luego hice el método de extensión para DbContext.

uso es simple.

db.Truncates(); // todas las tablas se eliminan.

db.Truncates ("Prueba1", "Prueba2"); // única "Prueba1, Test2" mesa de borrar

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

¡Muy bien! No pude hacer que TRUNCATE funcionara con una clave externa, incluso al guardar primero al padre y eliminar el contexto. –

2

me gustaría tratar de mejorar la gran respuesta de @Wojciech Markowski.

Si usted es perezoso como yo, y no desea comprobar si hay restricciones de claves foráneas, puede utilizar este método:

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

método ClearDatabase va sobre la lista de tablas y limpiarlos. si se encuentra la restricción FK, capture la excepción y pase a la siguiente tabla. al final se eliminarán todas las tablas.

Por otra parte, si no le importa perder todas las restricciones FK, puede desactivar todos ellos por la línea:

context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'"); 

Una cosa más: Si desea eliminar todas las tablas y no simplemente eliminarlas, a continuación, sustituya la línea:

context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count))); 

con:

context.Database.ExecuteSqlCommand(string.Format("DROP TABLE {0}", tableNames.ElementAt(i % tableNames.Count))); 

Personalmente comprobé esta respuesta en Entity Framework 6 con migración de código primero.

EDIT: mejor versión:

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

      } 

     } 

la sentencia if en cheques de bloque de captura si alcancé el último índice de la lista de tablas sin borrar cualquier tabla. En ese caso, en lugar de ir en un bucle infinito, lanza una excepción y sale del.

6

Para EF 6:

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

Esto sigue siendo actual para EF Core. – Grimley

Cuestiones relacionadas