Як мені видалити всі елементи з набору даних?


77

Який найкращий спосіб видалити всі елементи у System.Data.Entity.DbSet за допомогою Entity Framework 4.3?

Відповіді:


103
dbContext.Database.ExecuteSqlCommand("delete from MyTable");

(Без жартів.)

Проблема полягає в тому, що EF не підтримує жодних пакетних команд, і єдиним способом видалення всіх сутностей у наборі без використання прямого DML буде:

foreach (var entity in dbContext.MyEntities)
    dbContext.MyEntities.Remove(entity);
dbContext.SaveChanges();

Або, можливо, трохи дешевше, щоб уникнути завантаження повних об'єктів:

foreach (var id in dbContext.MyEntities.Select(e => e.Id))
{
    var entity = new MyEntity { Id = id };
    dbContext.MyEntities.Attach(entity);
    dbContext.MyEntities.Remove(entity);
}
dbContext.SaveChanges();

Але в обох випадках вам доведеться завантажити всі сутності або всі ключові властивості та видалити сутності по одному із набору. Більше того, при виклику SaveChangesEF надішле n (= кількість сутностей у наборі) операторів DELETE до бази даних, які також виконуються по одному в БД (за одну транзакцію).

Отже, прямий SQL для цієї мети переважно, оскільки вам потрібен лише один оператор DELETE.


2
Вам потрібно телефонувати SaveChangesпісля dbContext.Database.ExecuteSqlCommand?
PeterX 03.03.15

справжня проблема полягає в тому, як DbContext забезпечує доступ до всіх своїх DbSets / Entities? Немає можливості зациклюватися над ними, якщо ви не використовуєте роздуми. Це ви мали на увазі, посилаючись на "MyEntities"?
Веверке

2
Як щодо RemoveRangeзамість Remove? Чи могли б ви сказати, "що це було введено лише в EF 6, а OP запитували про EF 4. *"?
Червоний горох,

35

Стара публікація, але зараз існує метод RemoveRange:

    dbContext.MyEntities.RemoveRange(dbContext.MyEntities);
    dbContext.SaveChanges();

1
Я використовую цю відповідь, оскільки код простий і зрозумілий. Я впевнений, що існують більш ефективні способи зробити це, але я працюю з Azure WebJob, який буде працювати протягом ночі, тому на даний момент це не турбує.
Філ Рінгсмут,

Проблема RemoveRange полягає в тому, що вам все одно потрібно запитувати всі сутності з БД (або принаймні ідентифікатори), оскільки цей метод є просто обгорткою навколо foreach.
Szörényi Ádám

18

Ось ще один спосіб, як ви можете це зробити в коді.

public static class Extensions
{
    public static void DeleteAll<T>(this DbContext context)
        where T : class
    {
        foreach (var p in context.Set<T>())
        {
            context.Entry(p).State = EntityState.Deleted;
        }
    }
}

Щоб насправді викликати метод і очистити набір:

myDbContext.DeleteAll<MyPocoClassName>();


2

Як прийнята відповідь згадується лише про метод нижче:

context.Database.ExecuteSqlCommand("delete from MyTable");

і, скоріше, дає йому альтернативи, мені вдалося написати метод, за допомогою якого ви зможете уникнути завантаження всіх сутностей, а потім переглядати їх і використовувати замість цього ExecuteSqlCommand .

Припускаючи використання одиниці роботи, де контекстом є DbContext:

using System.Data.Entity.Core.Objects;
using System.Text.RegularExpressions;

public void DeleteAll()
{
    ObjectContext objectContext = ( (IObjectContextAdapter)context ).ObjectContext;
    string sql = objectContext.CreateObjectSet<T>().ToTraceString();
    Regex regex = new Regex( "FROM (?<table>.*) AS" );
    Match match = regex.Match( sql );
    string tableName = match.Groups[ "table" ].Value;

    context.Database.ExecuteSqlCommand( string.Format( "delete from {0}", tableName ) );
}

Перший блок коду отримує ім'я таблиці, необхідне в методі ExecuteSqlCommand .

Використання:

using ( var context = new UnitOfWork() )
{
    context.MyRepository.DeleteAll();
}

Не потрібно телефонувати

context.SaveChanges()

1

Якщо ви працюєте з одиницею роботи та загальним сховищем, вам може виявитися корисним наступне

public virtual void DeleteWhere(Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;
            if (filter != null)
            {
                query = query.Where(filter);
            }
            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            foreach (var entity in query)
            {
                context.Entry(entity).State = EntityState.Deleted;
            }
        }

Використання:

uow.myRepositoryName.DeleteWhere(u => u.RoomId == roomId);
uow.Save();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.