Wie kann ich mit Entity Framework schnell alle Zeilen in der Tabelle entfernen?
Ich benutze derzeit:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
Die Ausführung dauert jedoch lange.
Gibt es Alternativen?
Für diejenigen, die das googeln und wie ich hier gelandet sind, ist dies derzeit in EF5 und EF6 der Fall:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
Angenommen, der Kontext ist ein System.Data.Entity.DbContext
Warnung: Das Folgende ist nur für kleine Tabellen geeignet (denken Sie <1000 Zeilen)
In der folgenden Lösung werden die Zeilen mithilfe des Entity-Frameworks (nicht SQL) gelöscht, sodass es nicht für die SQL Engine (R/DBM) spezifisch ist.
Dies setzt voraus, dass Sie dies zum Testen oder in einer ähnlichen Situation tun. Entweder
Rufen Sie einfach an:
VotingContext.Votes.RemoveRange(VotingContext.Votes);
Angenommen, dieser Kontext:
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;}
}
Für saubereren Code können Sie die folgende Erweiterungsmethode deklarieren:
public static class EntityExtensions
{
public static void Clear<T>(this DbSet<T> dbSet) where T : class
{
dbSet.RemoveRange(dbSet);
}
}
Dann wird das Obige:
VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();
Vor kurzem habe ich diesen Ansatz verwendet, um meine Testdatenbank für jeden Testfalllauf zu bereinigen (dies ist offensichtlich schneller als jedes Mal eine Neuerstellung der Datenbank von Grund auf, obwohl ich die Form der generierten Löschbefehle nicht überprüft habe).
Warum kann es langsam sein?
Wenn Sie also mit einer großen Datenmenge arbeiten, beenden Sie den SQL Server-Prozess (er belegt den gesamten Speicher) und das Gleiche für den IIS) -Prozess, da EF alle Daten zwischenspeichert Genauso wie SQL Server. Verwenden Sie diesen nicht, wenn Ihre Tabelle eine ernsthafte Datenmenge enthält.
Verwenden von SQLs TRUNCATE TABLE
Befehl ist der schnellste, da er für die Tabelle und nicht für einzelne Zeilen ausgeführt wird.
dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
Angenommen, dataDb
ist ein DbContext
(kein ObjectContext
), können Sie es umbrechen und die folgende Methode verwenden:
var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
using (var context = new DataDb())
{
var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}
oder
using (var context = new DataDb())
{
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}
Dies vermeidet die Verwendung von SQL
using (var context = new MyDbContext())
{
var itemsToDelete = context.Set<MyTable>();
context.MyTables.RemoveRange(itemsToDelete);
context.SaveChanges();
}
Sie können das ohne Foreach tun
dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
Dadurch werden alle Zeilen entfernt
Ich bin auf diese Frage gestoßen, als ich mich mit einem bestimmten Fall befassen musste: vollständige Aktualisierung des Inhalts in einer "Blatt" -Tabelle (keine FKs, die darauf verweisen). Dies beinhaltete das Entfernen aller Zeilen und das Einfügen neuer Zeileninformationen und sollte transaktional erfolgen (ich möchte nicht mit einer leeren Tabelle enden, wenn Einfügungen aus irgendeinem Grund fehlschlagen).
Ich habe den Ansatz public static void Clear<T>(this DbSet<T> dbSet)
ausprobiert, aber es werden keine neuen Zeilen eingefügt. Ein weiterer Nachteil ist, dass der gesamte Prozess langsam ist, da die Zeilen einzeln gelöscht werden.
Also habe ich auf TRUNCATE
umgestellt, da es viel schneller ist und es auch ROLLBACKable ist. Es setzt auch die Identität zurück.
Beispiel mit Repository-Muster:
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();
Wie bereits erwähnt, kann diese Lösung natürlich nicht von Tabellen verwendet werden, auf die durch Fremdschlüssel verwiesen wird (TRUNCATE schlägt fehl).
wenn
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
}
ursachen
Die Tabelle 'MyTable' kann nicht abgeschnitten werden, da auf sie von einer FOREIGN KEY-Einschränkung verwiesen wird.
Ich benutze das :
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
}
Wenn Sie Ihre gesamte Datenbank löschen möchten.
Aufgrund der Fremdschlüsseleinschränkungen ist es wichtig, in welcher Reihenfolge die Tabellen abgeschnitten werden. Dies ist eine Möglichkeit, diese Sequenz zu brachialisieren.
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();
}
}
verwendungszweck:
ClearDatabase<ApplicationDbContext>();
denken Sie daran, Ihren DbContext danach erneut zu initialisieren.
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
Dies funktioniert ordnungsgemäß in EF 5:
YourEntityModel myEntities = new YourEntityModel();
var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");
Löschen Sie alle Datensätze. Setzen Sie den Primärindex nicht wie "Abschneiden" zurück.
/// <summary>
/// SET - DELETE all record by table - no truncate - return deleted records
/// </summary>
public static int setListDelAllMYTABLE()
{
// INIT
int retObj = 0;
using (MYDBEntities ctx = new MYDBEntities())
{
// GET - all record
var tempAllRecord = ctx.MYTABLE.ToList();
// RESET
ctx.MYTABLE.RemoveRange(tempAllRecord);
// SET - final save
retObj += ctx.SaveChanges();
}
// RET
return retObj;
}