Entity Framework. Удалить все строки в таблице

Как я могу быстро удалить все строки в таблице с помощью Entity Framework?

В настоящее время я использую:

var rows = from o in dataDb.Table
           select o;
foreach (var row in rows)
{
    dataDb.Table.Remove(row);
}
dataDb.SaveChanges();

Однако для выполнения требуется много времени.

Есть ли альтернативы?

Ответ 1

Для тех, кто занимается поиском в Google и заканчивается здесь, как и я, так вы сейчас это делаете в EF5 и EF6:

context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");

Предполагаемый контекст - это System.Data.Entity.DbContext

Ответ 2

Предупреждение: следующее подходит только для небольших таблиц (например, <1000 строк)

Вот решение, которое использует структуру сущностей (не SQL) для удаления строк, поэтому оно не является специфичным для SQL Engine (R/DBM).

Это предполагает, что вы делаете это для тестирования или какой-то подобной ситуации. Или

  • Количество данных мало или
  • Производительность не имеет значения

Просто позвоните:

VotingContext.Votes.RemoveRange(VotingContext.Votes);

Предполагая этот контекст:

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;}
}

Для более простого кода вы можете объявить следующий метод расширения:

public static class EntityExtensions
{
    public static void Clear<T>(this DbSet<T> dbSet) where T : class
    {
        dbSet.RemoveRange(dbSet);
    }
}

Тогда выше становится:

VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();

Недавно я использовал этот подход для очистки своей тестовой базы данных при каждом запуске тестового набора (это, очевидно, быстрее, чем воссоздание БД с нуля каждый раз, хотя я не проверял форму сгенерированных команд удаления).


Почему это может быть медленным?

  1. EF получит ВСЕ строки (VotingContext.Votes)
  2. а затем будет использовать их идентификаторы (не знаю точно, как, не имеет значения), чтобы удалить их.

Поэтому, если вы работаете с серьезным объемом данных, вы убьете процесс сервера SQL (он будет занимать всю память) и то же самое для процесса IIS, поскольку EF будет кэшировать все данные так же, как сервер SQL. Не используйте этот, если ваша таблица содержит серьезный объем данных.

Ответ 3

Использование SQL TRUNCATE TABLE команда будет самой быстрой, поскольку она работает на таблице, а не на отдельных строках.

dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");

Предполагая, что dataDb является DbContext (а не ObjectContext), вы можете его обернуть и использовать метод следующим образом:

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");

Ответ 4

var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();

Ответ 5

using (var context = new DataDb())
{
     var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
     ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}

или

using (var context = new DataDb())
{
     context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}

Ответ 6

Это позволяет избежать использования любого sql

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}

Ответ 7

Вы можете сделать это без Foreach

dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();

Это удалит все строки

Ответ 8

Я сталкивался с этим вопросом, когда мне приходилось иметь дело с конкретным случаем: полным обновлением контента в "листовой" таблице (без ФК, указывающих на это). Это включало удаление всех строк и добавление информации о новых строках, и это должно быть сделано транзакционно (я не хочу заканчивать с пустой таблицей, если вставки терпят неудачу по любой причине).

Я пробовал public static void Clear<T>(this DbSet<T> dbSet) подход public static void Clear<T>(this DbSet<T> dbSet), но новые строки не вставляются. Другим недостатком является то, что весь процесс идет медленно, так как строки удаляются одна за другой.

Итак, я переключился на подход TRUNCATE, так как он намного быстрее и также ROLLBACKable. Это также сбрасывает личность.

Пример использования шаблона хранилища:

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();

Конечно, как уже упоминалось, это решение не может быть использовано в таблицах, на которые ссылаются внешние ключи (сбой TRUNCATE).

Ответ 9

Как сказал Руди Виссер:

Использование команды SQL TRUNCATE TABLE будет самой быстрой, поскольку она работает в таблице, а не в отдельных строках.

dataDb.ExecuteStoreCommand( "TRUNCATE TABLE [Таблица]" );

Предполагая, что dataDb является DbContext (а не ObjectContext), вы можете его обернуть и использовать метод следующим образом:

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter) dataDb).ObjectContext; objCtx.ExecuteStoreCommand( "TRUNCATE TABLE [Таблица]" );

Но вы должны быть осторожны, чтобы использовать после себя где-то только что созданный файл данных - иначе вы столкнетесь с конфликтами структуры организации. Внутри datacontext эти объекты все еще живы при использовании таблицы Truncate.

Ответ 10

если

      using(var db = new MyDbContext())
            {
               await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
            }

вызывает

Невозможно обрезать таблицу "MyTable", потому что на нее ссылается ограничение FOREIGN KEY.

Я использую это:

      using(var db = new MyDbContext())
               {
                   await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
               }

Ответ 11

Если вы хотите очистить всю базу данных.

Из-за ограничений внешнего ключа важно, какая последовательность усечена. Это способ выполнить эту последовательность.

    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();
        }
    }

использование:

ClearDatabase<ApplicationDbContext>();

помните, что после этого повторно создайте свой DbContext.

Ответ 12

var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();

Ответ 13

Это правильно работает в EF 5:

YourEntityModel myEntities = new YourEntityModel();

var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");

Ответ 14

Удалить все записи. Не сбрасывайте основной индекс, как "усекать".

/// <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;
}

Ответ 15

В моем коде у меня не было хорошего доступа к объекту Database, так что вы можете сделать это в DbSet, где вам также разрешено использовать любой тип sql. Это будет примерно так:

var p = await _db.Persons.FromSql("truncate table Persons;select top 0 * from Persons").ToListAsync();

Ответ 16

Следующее работает с базой данных SQLite (используя Entity Framework)

Похоже, что самый быстрый способ очистить все таблицы БД - это использовать context.Database.ExecuteSqlCommand("некоторый SQL"), как отмечалось выше в некоторых комментариях. Здесь я собираюсь показать, как сбросить счетчик 'index' таблиц.

            context.Database.ExecuteSqlCommand("delete from TableA");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableA'");//resets the autoindex

            context.Database.ExecuteSqlCommand("delete from TableB");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableB'");//resets the autoindex 

            context.Database.ExecuteSqlCommand("delete from TableC");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableC'");//resets the autoindex 

Одним из важных моментов является то, что если вы используете внешние ключи в своих таблицах, вы должны сначала удалить дочернюю таблицу перед родительской таблицей, поэтому важна последовательность (иерархия) таблиц при удалении, в противном случае может возникнуть исключение SQLite.

Примечание: var context = new YourContext()