Ich möchte den Inhalt aller Tabellen (alle Entitäten) mit Entity Framework 4+ löschen. Wie kann das gemacht werden?
Antworten
Zu viele Anzeigen?Das wird viel bringen, viel besser als alles, was das Löschen einzelner Entitätsobjekte beinhaltet, vorausgesetzt, die zugrunde liegende Datenbank ist MSSQL.
foreach (var tableName in listOfTableNames)
{
context.ExecuteStoreCommand("TRUNCATE TABLE [" + tableName + "]");
}
Wenn Ihre Tabellen Fremdschlüsselbeziehungen haben, müssen Sie Ihre Liste der Tabellennamen natürlich in der richtigen Reihenfolge einrichten, damit Sie die Fremdschlüsseltabellen löschen, bevor Sie die Primärschlüsseltabellen löschen, von denen sie möglicherweise abhängen.
Nur für Faule, den Code habe ich mir selbst ausgedacht, als ich nach der Antwort suchte:
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();
}
}
Kurze Erklärung: Ich schneide keine Tabellen aufgrund fehlender Berechtigungen ab, wenn es für Sie kein Problem ist, können Sie das gerne tun. Die Tabelle __MigrationHistory wird von der where-Anweisung ignoriert.
UPDATE: Nach einigen Recherchen habe ich eine bessere Lösung gefunden (nicht so schön, aber es werden nur die erforderlichen Spalten gelöscht):
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();
}
Iterieren Sie durch die Tabellen mit einem Code wie diesem:
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.
}
);
Ich möchte versuchen, die großartige Antwort von @Wojciech Markowski zu verbessern.
Wenn Sie so faul sind wie ich und nicht nach Fremdschlüssel-Beschränkungen suchen wollen, können Sie diese Methode verwenden:
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-Methode geht über die Liste der Tabellen und bereinigen Sie sie. Wenn FK-Beschränkung gefunden wird, dann fangen die Ausnahme und gehen Sie auf die nächste Tabelle. Am Ende werden alle Tabellen gelöscht.
Wenn es Ihnen nichts ausmacht, alle FK-Zwangsbedingungen zu verlieren, können Sie sie auch alle in der Zeile deaktivieren:
context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");
Eine Sache noch: Wenn Sie alle Tabellen löschen und nicht nur löschen wollen, dann ersetzen Sie die Zeile:
context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
mit:
context.Database.ExecuteSqlCommand(string.Format("DROP TABLE {0}", tableNames.ElementAt(i % tableNames.Count)));
Ich persönlich habe diese Antwort auf Entity Framework 6 mit Code-First-Migration überprüft.
EDITAR: bessere Version:
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);
}
}
}
die if-Anweisung im catch-Block prüft, ob ich den letzten Index der Tabellenliste erreicht habe, ohne eine Tabelle zu löschen. In diesem Fall sollten Sie, anstatt in eine Endlosschleife zu gehen, eine Ausnahme auslösen und den for-Block verlassen.
- See previous answers
- Weitere Antworten anzeigen