Как удалить несколько строк в Entity Framework (без foreach) - PullRequest
280 голосов
/ 26 марта 2010

Я удаляю несколько элементов из таблицы, используя Entity Framework. Не существует внешнего ключа / родительского объекта, поэтому я не могу справиться с этим с помощью OnDeleteCascade.

Прямо сейчас я делаю это:

var widgets = context.Widgets
    .Where(w => w.WidgetId == widgetId);

foreach (Widget widget in widgets)
{
    context.Widgets.DeleteObject(widget);
}
context.SaveChanges();

Это работает, но меня раздражает foreach. Я использую EF4, но я не хочу выполнять SQL. Я просто хочу убедиться, что я ничего не пропустил - это так хорошо, как получается, верно? Я могу абстрагировать его с помощью метода расширения или помощника, но где-то мы все еще будем делать foreach, верно?

Ответы [ 19 ]

3 голосов
/ 18 февраля 2015

Если вы хотите удалить все строки таблицы, вы можете выполнить команду sql

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

TRUNCATE TABLE (Transact-SQL) Удаляет все строки из таблицы без регистрации удалений отдельных строк. TRUNCATE TABLE похож на инструкцию DELETE без предложения WHERE; однако TRUNCATE TABLE работает быстрее и использует меньше ресурсов системы и журнала транзакций.

3 голосов
/ 21 ноября 2016

Для этого можно использовать библиотеки расширений, такие как EntityFramework.Extended или Z.EntityFramework.Plus.EF6, которые доступны для EF 5, 6 или Core. Эти библиотеки имеют отличную производительность, когда вам нужно удалить или обновить, и они используют LINQ. Пример удаления ( источник плюс ):

ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2)) .Delete();

или ( источник расширен )

context.Users.Where(u => u.FirstName == "firstname") .Delete();

В них используются нативные операторы SQL, поэтому производительность великолепна.

2 голосов
/ 12 декабря 2016

UUHHIVS - очень элегантный и быстрый способ удаления партии, но его следует использовать с осторожностью:

  • автоматическое создание транзакции: ее запросы будут охватываться транзакцией
  • независимость от контекста базы данных: ее выполнение не имеет ничего общего с context.SaveChanges()

Эти проблемы можно обойти, взяв под контроль транзакцию. Следующий код иллюстрирует, как пакетное удаление и массовая вставка транзакционным способом:

var repo = DataAccess.EntityRepository;
var existingData = repo.All.Where(x => x.ParentId == parentId);  

TransactionScope scope = null;
try
{
    // this starts the outer transaction 
    using (scope = new TransactionScope(TransactionScopeOption.Required))
    {
        // this starts and commits an inner transaction
        existingData.Delete();

        // var toInsert = ... 

        // this relies on EntityFramework.BulkInsert library
        repo.BulkInsert(toInsert);

        // any other context changes can be performed

        // this starts and commit an inner transaction
        DataAccess.SaveChanges();

        // this commit the outer transaction
        scope.Complete();
    }
}
catch (Exception exc)
{
    // this also rollbacks any pending transactions
    scope?.Dispose();
}
1 голос
/ 24 сентября 2014

Вы также можете использовать метод DeleteAllOnSubmit () , передав его результаты в общий список , а не в var. Таким образом, ваш foreach сокращается до одной строки кода:

List<Widgets> widgetList = context.Widgets
              .Where(w => w.WidgetId == widgetId).ToList<Widgets>();

context.Widgets.DeleteAllOnSubmit(widgetList);

context.SubmitChanges();

Возможно, он все еще использует цикл внутри.

1 голос
/ 26 мая 2014

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

    private int DeleteData()
{
    using (var ctx = new MyEntities(this.ConnectionString))
    {
        if (ctx != null)
        {

            //Delete command
            return ctx.ExecuteStoreCommand("DELETE FROM ALARM WHERE AlarmID > 100");

        }
    }
    return 0;
}

Для выбора мы можем использовать

using (var context = new MyContext()) 
{ 
    var blogs = context.MyTable.SqlQuery("SELECT * FROM dbo.MyTable").ToList(); 
}
0 голосов
/ 24 января 2019

В EF 6.2 это работает отлично, отправляя удаление непосредственно в базу данных без предварительной загрузки сущностей:

context.Widgets.Where(predicate).Delete();

С фиксированным предикатом это довольно просто:

context.Widgets.Where(w => w.WidgetId == widgetId).Delete();

И если вам нужен динамический предикат, посмотрите на LINQKit (доступен пакет Nuget), в моем случае что-то вроде этого отлично работает:

Expression<Func<Widget, bool>> predicate = PredicateBuilder.New<Widget>(x => x.UserID == userID);
if (somePropertyValue != null)
{
    predicate = predicate.And(w => w.SomeProperty == somePropertyValue);
}
context.Widgets.Where(predicate).Delete();
0 голосов
/ 25 октября 2014

EF 6. =>

var assignmentAddedContent = dbHazirBot.tbl_AssignmentAddedContent.Where(a =>
a.HazirBot_CategoryAssignmentID == categoryAssignment.HazirBot_CategoryAssignmentID);
dbHazirBot.tbl_AssignmentAddedContent.RemoveRange(assignmentAddedContent);
dbHazirBot.SaveChanges();
0 голосов
/ 21 февраля 2014

См. Ответ «любимый бит кода», который работает

Вот как я это использовал:

     // Delete all rows from the WebLog table via the EF database context object
    // using a where clause that returns an IEnumerable typed list WebLog class 
    public IEnumerable<WebLog> DeleteAllWebLogEntries()
    {
        IEnumerable<WebLog> myEntities = context.WebLog.Where(e => e.WebLog_ID > 0);
        context.WebLog.RemoveRange(myEntities);
        context.SaveChanges();

        return myEntities;
    }
0 голосов
/ 10 января 2016

Лучше: in EF6 => .RemoveRange()

Пример:

db.Table.RemoveRange(db.Table.Where(x => Field == "Something"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...