c# - query - Marco de la entidad. Eliminar todas las filas en la tabla
linq inner join c# entity framework (12)
¿Cómo puedo eliminar rápidamente todas las filas de la tabla utilizando Entity Framework?
Actualmente estoy usando:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
Sin embargo, tarda mucho tiempo en ejecutarse.
¿Hay alguna alternativa?
El uso del comando TRUNCATE TABLE
SQL será el más rápido, ya que opera en la tabla y no en filas individuales.
dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
Suponiendo que dataDb
es un DbContext
(no un ObjectContext
), puede envolverlo y usar el método así:
var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
Esto evita el uso de cualquier sql
using (var context = new MyDbContext())
{
var itemsToDelete = context.Set<MyTable>();
context.MyTables.RemoveRange(itemsToDelete);
context.SaveChanges();
}
Esto funciona correctamente en EF 5:
YourEntityModel myEntities = new YourEntityModel();
var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");
Me encontré con esta pregunta cuando tuve que lidiar con un caso particular: actualización completa del contenido en una tabla "hoja" (no hay FK que lo indiquen). Esto implicó eliminar todas las filas y colocar información sobre las nuevas filas y se debe hacer de forma transaccional (no quiero terminar con una tabla vacía, si las inserciones fallan por alguna razón).
He intentado el public static void Clear<T>(this DbSet<T> dbSet)
, pero no se insertan nuevas filas. Otro inconveniente es que todo el proceso es lento, ya que las filas se eliminan una por una.
Por lo tanto, he cambiado al enfoque TRUNCATE
, ya que es mucho más rápido y también es ROLLBACKable . También restablece la identidad.
Ejemplo usando patrón de repositorio:
public class Repository<T> : IRepository<T> where T : class, new()
{
private readonly IEfDbContext _context;
public void BulkInsert(IEnumerable<T> entities)
{
_context.BulkInsert(entities);
}
public void Truncate()
{
_context.Database.ExecuteSqlCommand($"TRUNCATE TABLE {typeof(T).Name}");
}
}
// usage
DataAccess.TheRepository.Truncate();
var toAddBulk = new List<EnvironmentXImportingSystem>();
// fill toAddBulk from source system
// ...
DataAccess.TheRepository.BulkInsert(toAddBulk);
DataAccess.SaveChanges();
Por supuesto, como ya se mencionó, esta solución no puede ser utilizada por tablas a las que se hace referencia por claves externas (falla TRUNCATE).
Para aquellos que están buscando en Google y terminaron aquí como yo, así es como lo hacen actualmente en EF5 y EF6:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
Suponiendo que el contexto es un System.Data.Entity.DbContext
Puedes hacerlo sin Foreach
dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
Esto eliminará todas las filas
Si
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
}
causas
No se puede truncar la tabla ''MyTable'' porque está referenciada por una restricción FOREIGN KEY.
Yo uso esto :
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
}
Si desea borrar toda su base de datos.
Debido a las restricciones de clave foránea, importa qué secuencia se truncan las tablas. Esta es una forma de fuerza bruta de esta secuencia.
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)
{
foreach (var t in tableNames)
{
try
{
if (context.Database.ExecuteSqlCommand(string.Format("TRUNCATE TABLE [{0}]", tableName)) == 1)
break;
}
catch (Exception ex)
{
}
}
}
context.SaveChanges();
}
}
uso:
ClearDatabase<ApplicationDbContext>();
Recuerde volver a establecer su DbContext después de esto.
Advertencia: lo siguiente solo es adecuado para tablas pequeñas (piense en <1000 filas)
Aquí hay una solución que utiliza el marco de la entidad (no SQL) para eliminar las filas, por lo que no es específico del Motor SQL (R / DBM).
Esto supone que estás haciendo esto para probar o alguna situación similar. Ya sea
- La cantidad de datos es pequeña o
- El rendimiento no importa.
Simplemente llame:
VotingContext.Votes.RemoveRange(VotingContext.Votes);
Asumiendo este contexto:
public class VotingContext : DbContext
{
public DbSet<Vote> Votes{get;set;}
public DbSet<Poll> Polls{get;set;}
public DbSet<Voter> Voters{get;set;}
public DbSet<Candidacy> Candidates{get;set;}
}
Para código más ordenado puede declarar el siguiente método de extensión:
public static class EntityExtensions
{
public static void Clear<T>(this DbSet<T> dbSet) where T : class
{
dbSet.RemoveRange(dbSet);
}
}
Entonces lo anterior se convierte en:
VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();
Recientemente utilicé este método para limpiar mi base de datos de prueba para cada ejecución de prueba (obviamente es más rápido que volver a crear el DB desde cero cada vez, aunque no verifiqué la forma de los comandos de eliminación que se generaron).
¿Por qué puede ser lento?
- EF obtendrá TODAS las filas (VotingContext.Votes)
- y luego usarán sus ID (no sé exactamente cómo, no importa), para eliminarlos.
Entonces, si está trabajando con una gran cantidad de datos, eliminará el proceso del servidor SQL (consumirá toda la memoria) y lo mismo para el proceso IIS, ya que EF almacenará en caché todos los datos de la misma manera que el servidor SQL. No use este si su tabla contiene una gran cantidad de datos.
using (var context = new DataDb())
{
var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}
o
using (var context = new DataDb())
{
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();