Удаление всех сущностей в Entity Framework
Я хочу удалить содержимое всех таблиц (все сущности) с помощью Entity Framework 4+. Как это можно сделать?
6 ответов:
Это будет работать гораздо, много лучше, чем что-либо, связанное с удалением отдельных объектов сущности, предполагая, что базовая база данных-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(); } }
краткое описание: Я не усекаю таблицы из-за отсутствия разрешений, если это не проблема для вас, не стесняйтесь делать это. Таблица __MigrationHistory игнорируется оператором where.
обновление: после некоторых исследований я придумал лучшее решение (не так хорошо, но удаляет только нужные столбцы):
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(); }
перебираем таблицы с кодом примерно так:
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. } );
Я хотел бы попытаться улучшить отличный ответ @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 с первой миграцией кода.
EDIT: лучше вариант:
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.
усечение не удалось удалить в пределах внешнего ключа.
затем я сделал метод расширения для DbContext.
использование просто.
db.Усекает (); / / все таблицы удаляются.
db.Усекает ("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(); } }