Групове видалення в LINQ для сутностей


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

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

1
Обережно github.com/loresoft/EntityFramework.Extended має залежність від EF5, якщо ви використовуєте менеджер NuGet пакет консолі , щоб встановити його, то це буде не питаючи установки EF5
Пол Захра

1
Це насправді не допомагає - я хотів би бачити робочий приклад команди Delete, а не "вгадувати", як реалізувати свій власний у виробничому коді і, можливо, щось зіпсувати. -1
нуццоліло

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

+! ... при використанні БД ви виявите, що потрібним вам інструментом є викрутка .. 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 ("ВИДАЛИТИ З ВАШОЇ ТАБЛИЦІ ДЕ 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 перераховує всі об'єкти, що відповідають вашому запиту, а потім перебирає їх вручну, щоб їх видалити. Звичайно, ітерація відбувається в БД, а не у вашому коді, але ви все одно марно створюєте набір результатів лише для того, щоб видалити його вміст - все ще набагато гірше, ніж просте "ВИДАЛИТИ З таблиці, ДЕ 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 ("ВИДАЛИТИ ...") ;. Також далеко не ідеально, але це спрацювало б.
Скотт Андерсон,

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

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

@G Дженні Рамірес додала моє рішення.
Demodave

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