Массовое удаление в LINQ to Entities


82

Есть ли способ массового удаления группы объектов, соответствующих данному запросу, в LINQ или LINQ-to-Entities? Единственные ссылки, которые я могу найти, устарели, и кажется глупым перебирать и вручную удалять все объекты, которые я хочу удалить.

Ответы:



53

Некоторое время назад я написал серию блогов из 4 частей (части 1 , 2 , 3 и 4 ), в которых рассказывается о выполнении массовых обновлений (с помощью одной команды) в Entity Framework.

Хотя основное внимание в этой серии было уделено обновлению, вы определенно могли использовать соответствующие принципы для удаления.

Итак, вы должны иметь возможность написать что-то вроде этого:

var query = from c in ctx.Customers
            where c.SalesPerson.Email == "..."
            select c;

query.Delete();

Все, что вам нужно сделать, это реализовать метод расширения Delete (). Смотрите серию постов, чтобы узнать, как ...

Надеюсь это поможет


17
Было бы неплохо иметь здесь образец кода, если он есть у кого-нибудь!
jocull 04

1
Множество методов расширения (включая пакетное удаление) можно найти здесь: github.com/loresoft/EntityFramework.Extended
Soliah

1
Остерегайтесь github.com/loresoft/EntityFramework.Extended зависит от EF5, если вы используете консоль диспетчера пакетов Nuget для его установки, она установит EF5, не спрашивая вас,
Пол Захра

1
На самом деле это не помогает - я бы хотел увидеть рабочий пример команды «Удалить», а не «угадывать», как реализовать свою собственную в производственном коде и, возможно, что-то напортачить. -1
nuzzolilo 05

27
Хм ... так что ответ на вопрос - перенаправить на 4 сообщения в блоге вместо того, чтобы представлять конкретный ответ аудитории.
DeepSpace101,

41
    using (var context = new DatabaseEntities())
    {
        // delete existing records
        context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
    }

3
+1 - Приятно видеть пример кода, показывающий, как выполнить код SQL с использованием EF
Карлос П.

2
Я понимаю, что это, вероятно, единственный способ сделать это, за исключением создания хранимой процедуры, но это похоже на обман =). Теперь, когда я использую это, у меня возникает соблазн использовать его в нескольких других местах, чтобы избавиться от причудливости EF, лол - например, сложных левых объединений и групповых байтов ... :)
Losbear

+! ... при использовании DB вы обнаружите, что вам нужен отвертка ... EF - это просто еще один молоток.
gbjbaanb

2
Небольшой недостаток: теперь у вас есть команда базы данных, которая отключена от среды разработки. Он не строго типизирован, поэтому изменение базы данных для столбцов в этом SQL не будет выделено в Visual Studio
Ян

7

Ответы, которые я здесь вижу, - это Linq to Sql

DeleteAllOnSubmit является частью System.Data.Linq и ITable, которые являются Linq to Sql

Это невозможно сделать с помощью Entity Framework.

Сказав все это, у меня еще нет решения, но я отправлю его, когда сделаю


5

Для тех, кто использует EF6 и хочет выполнить строковый SQL-запрос для удаления:

using (var context = new DatabaseEntities())
{
    // delete existing records
    context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter);
}

1
Это сработало для меня в EF 5, но мне пришлось использовать @ p0 для параметра. Что приятно, так это то, что он обеспечивает проверку безопасных параметров в сгенерированном sql: поэтому в EF5 это будет работать: context.Database.ExecuteSqlCommand ("УДАЛИТЬ ИЗ ТАБЛИЦЫ WHERE CustomerID = @ p0", idParameter); \ @ p1 для следующего параметра и т. д.
Натан Пратер,

3

RemoveRange был введен в EF6, он может удалять список объектов. Очень просто.

var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList();
db.PermitOrigins.RemoveRange(origins);
db.SaveChanges();

1
Хотя этот фрагмент кода может решить вопрос, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причины вашего предложения кода.
DimaSan

2

Я знаю метод DeleteAllOnSubmit любого контекста данных, который удалит все записи в запросе. В основе должна быть некоторая оптимизация, поскольку удаляется много объектов. Хотя я не уверен.


3
На самом деле никакой оптимизации не происходит. Сгенерированный SQL перечисляет все объекты, соответствующие вашему запросу, а затем вручную перебирает их, чтобы удалить. Конечно, итерация происходит в БД, а не в вашем коде, но вы по-прежнему без нужды создаете набор результатов просто для удаления его содержимого - все еще намного хуже, чем простое «УДАЛИТЬ ИЗ таблицы WHERE foo = bar», которое строит нет набора результатов и покрывает таблицу только один раз.
Бенджамин Поллак,

2

Не уверен, насколько это будет эффективно, но вы можете попробовать что-то вроде этого:

// deletes all "People" with the name "Joe"
var mypeople = from p in myDataContext.People
               where p.Name == "Joe";
               select p;
myDataContext.People.DeleteAllOnSubmit(mypeople);
myDataContext.SubmitChanges();

1
Это по-прежнему приводит к перебору всех элементов, соответствующих запросу; он просто делает это в БД, а не в вашем коде. Более эффективное, но все же далеко не идеальное решение.
Бенджамин Поллак,

3
Единственный другой способ, который я мог придумать, - это выполнить myDataContext.ExecuteCommand ("DELETE ...") ;. Тоже далеко не идеально, но это сработает.
Скотт Андерсон

1

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


1

Удаление данных через Entity Framework зависит от использования метода DeleteObject. Вы можете вызвать этот метод в EntityCollection для класса сущности, который вы хотите удалить, или в производном ObjectContext. Вот простой пример:

NorthwindEntities db = new NorthwindEntities();

IEnumerable<Order_Detail> ods = from o in db.Order_Details
                                where o.OrderID == 12345                                    
                                select o;

foreach (Order_Detail od in ods) 
    db.Order_Details.DeleteObject(od);

db.SaveChanges();

Однако это не «массовое удаление».
nuzzolilo 05

1

В этом примере я получаю записи для удаления и одну за другой прикрепляю их к набору результатов, а затем запрашиваю их удаление. Затем у меня есть 1 сохранение изменений.

    using (BillingDB db = new BillingDB())
    {
      var recordsToDelete = (from i in db.sales_order_item
                  where i.sales_order_id == shoppingCartId
                  select i).ToList<sales_order_item>();

      if(recordsToDelete.Count > 0)
      {
        foreach (var deleteSalesOrderItem in recordsToDelete)
        {                  
            db.sales_order_item.Attach(deleteSalesOrderItem);
            db.sales_order_item.Remove(deleteSalesOrderItem);                  
        }
        db.SaveChanges();
      } 
    }

1
 context.Entity.Where(p => p.col== id)
               .ToList().ForEach(p => db.Entity.DeleteObject(p));

это самый быстрый способ удалить запись из БД с помощью EF


0

Я бы сделал что-то вроде:

var recordsToDelete = (from c in db.Candidates_T where c.MyField == null select c).ToList<Candidates_T>();
if(recordsToDelete.Count > 0)
{
    foreach(var record in recordsToDelete)
    {
        db.Candidate_T.DeleteObject(record);
        db.SaveChanges();
    }
}   

Я не думаю, что есть способ сделать это без цикла, поскольку Entity Framework работает с Entities и в большинстве случаев это означает сбор объектов.


Вы также можете поделиться тем, что сделали. Благодарю.
Джени Рамирес,

@G Jeny Ramirez Добавил свое решение.
Demodave

2
@GJennyRamirez также в вашем примере вы сохраняете изменения несколько раз, и я думаю, вы можете вытащить это из цикла foreach и выполнить один раз
Demodave
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.