Який найкращий спосіб видалити всі елементи у System.Data.Entity.DbSet за допомогою Entity Framework 4.3?
Відповіді:
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();
Але в обох випадках вам доведеться завантажити всі сутності або всі ключові властивості та видалити сутності по одному із набору. Більше того, при виклику SaveChanges
EF надішле n (= кількість сутностей у наборі) операторів DELETE до бази даних, які також виконуються по одному в БД (за одну транзакцію).
Отже, прямий SQL для цієї мети переважно, оскільки вам потрібен лише один оператор DELETE.
RemoveRange
замість Remove
? Чи могли б ви сказати, "що це було введено лише в EF 6, а OP запитували про EF 4. *"?
Стара публікація, але зараз існує метод RemoveRange:
dbContext.MyEntities.RemoveRange(dbContext.MyEntities);
dbContext.SaveChanges();
Ось ще один спосіб, як ви можете це зробити в коді.
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>();
Якщо ви хочете видалити всі елементи без написання будь-якого SQL і виконати лише одиничний виклик Db
Розширена бібліотека Entity Framework пропонує метод пакетного видалення .
context.Users.Delete();
Як прийнята відповідь згадується лише про метод нижче:
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()
Якщо ви працюєте з одиницею роботи та загальним сховищем, вам може виявитися корисним наступне
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();
SaveChanges
післяdbContext.Database.ExecuteSqlCommand
?