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();
Недавно я использовал этот подход для очистки своей тестовой базы данных при каждом запуске тестового набора (это, очевидно, быстрее, чем воссоздание БД с нуля каждый раз, хотя я не проверял форму сгенерированных команд удаления).
Почему это может быть медленным?
- EF получит ВСЕ строки (VotingContext.Votes)
- а затем будет использовать их идентификаторы (не знаю точно, как, не имеет значения), чтобы удалить их.
Поэтому, если вы работаете с серьезным объемом данных, вы убьете процесс сервера 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()