Удалить все объекты в Entity Framework - PullRequest
53 голосов
/ 22 мая 2011

Я хочу удалить содержимое всех таблиц (всех сущностей), используя Entity Framework 4+. Как это можно сделать?

Ответы [ 6 ]

45 голосов
/ 22 мая 2011

Это будет работать намного, намного лучше, чем все, что связано с удалением отдельных объектов сущности, при условии, что основной базой данных является MSSQL.

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

Конечно, если ваши таблицы имеют отношения с внешним ключом, вам необходимо настроить список имен таблиц в правильном порядке, чтобы вы очищали таблицы с внешним ключом, прежде чем очищать любые таблицы первичных ключей, чтобы они могли зависит от.

13 голосов
/ 30 октября 2012

Только для ленивых, код я придумал сам, ища ответ:

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();
    }
7 голосов
/ 16 октября 2015

для EF 6:

DbSet<Entity>.RemoveRange(DbSet<Entity>);
3 голосов
/ 22 мая 2011

Итерация по таблицам с кодом, похожим на этот:

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.
}
);
2 голосов
/ 23 июня 2015

Я хотел бы попытаться улучшить отличный ответ @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'");

OneБолее того: если вы хотите удалить все таблицы, а не просто очистить их, замените строку:

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с миграцией кода вначале.

РЕДАКТИРОВАТЬ: лучшая версия:

        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.

1 голос
/ 28 августа 2014

усечение не удалось удалить из внешнего ключа.

тогда я сделал метод расширения для DbContext.

Использование просто.

db.Truncates (); // все таблицы удаляются.

db.Truncates ("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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...