Massenlöschen in LINQ to Entities


82

Gibt es eine Möglichkeit, eine Reihe von Objekten, die mit einer bestimmten Abfrage in LINQ oder LINQ-to-Entities übereinstimmen, in großen Mengen zu löschen? Die einzigen Referenzen, die ich finden kann, sind veraltet, und es scheint albern, alle Objekte, die ich entfernen möchte, zu durchlaufen und manuell zu löschen.

Antworten:



53

Vor einiger Zeit habe ich eine vierteilige Blogserie (Teile 1 , 2 , 3 und 4 ) geschrieben, in der es darum geht, Massenaktualisierungen (mit einem Befehl) im Entity Framework durchzuführen.

Während der Schwerpunkt dieser Serie auf der Aktualisierung lag, konnten Sie die Prinzipien definitiv zum Löschen verwenden.

Sie sollten also in der Lage sein, so etwas zu schreiben:

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

query.Delete();

Sie müssen lediglich die Erweiterungsmethode Delete () implementieren. In der Beitragsreihe finden Sie Hinweise, wie ...

Hoffe das hilft


17
Wäre schön, hier ein Codebeispiel dafür zu haben, wenn jemand es hat!
Jocull

1
Eine Reihe von Erweiterungsmethoden (einschließlich eines Batch-Löschvorgangs) finden Sie hier: github.com/loresoft/EntityFramework.Extended
Soliah

1
Vorsicht github.com/loresoft/EntityFramework.Extended hat eine Abhängigkeit von EF5. Wenn Sie Nuget Package Manager Console verwenden, um es zu installieren, wird EF5
Paul Zahra

1
Es hilft nicht wirklich - ich würde gerne ein funktionierendes Beispiel für einen Löschbefehl sehen und nicht "raten", wie ich meinen eigenen in Produktionscode implementieren und möglicherweise etwas vermasseln kann. -1
Nuzzolilo

27
Hm ... die Antwort auf die Frage besteht also darin, zu 4 Blog-Posts umzuleiten, anstatt die spezifische Antwort dem Publikum zu präsentieren.
DeepSpace101

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

3
+1 - Schön, ein Codebeispiel zu sehen, wie man SQL-Code mit EF ausführt
Carlos P

2
Mir ist klar, dass dies wahrscheinlich der einzige Weg ist, dies zu tun, ohne eine gespeicherte Prozedur zu erstellen, aber das fühlt sich an wie Betrug =). Nun , da ich dies mit, ich bin versucht , es in mehreren anderen Orten zu cicumvent EF Schrulligkeit lol zu verwenden - wie komplexe links schließt sich und die Gruppe bys ..... :)
Losbear

+! ... wenn Sie eine DB verwenden, werden Sie feststellen, dass das gewünschte Werkzeug ein Schraubendreher ist. EF ist nur ein weiterer Hammer.
Gbjbaanb

2
Ein kleiner Nachteil: Sie haben jetzt einen Datenbankbefehl, der von der Entwicklungsumgebung getrennt ist. Es ist nicht stark typisiert, so dass eine Änderung in der Datenbank für Spalten in dieser SQL wird nicht hervorgehoben werden in Visual Studio
Ian

7

Die Antworten, die ich hier sehe, sind Linq to Sql

DeleteAllOnSubmit ist Teil von System.Data.Linq und ITable (Linq to Sql)

Dies ist mit Entity Framework nicht möglich.

Trotzdem habe ich noch keine Lösung, werde aber zurückschreiben, wenn ich das tue


5

Für diejenigen, die EF6 verwenden und eine Zeilen-SQL-Abfrage zum Löschen ausführen möchten:

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

1
Dies funktionierte für mich in EF 5, aber ich musste @ p0 für den Parameter verwenden. Das Schöne ist, dass es eine typsichere Parameterprüfung in der generierten SQL bietet: In EF5 würde dies also funktionieren: context.Database.ExecuteSqlCommand ("DELETE FROM YOURTABLE WHERE CustomerID = @ p0", idParameter); \ @ p1 für den nächsten Parameter usw.
Nathan Prather

3

RemoveRange wurde in EF6 eingeführt und kann eine Liste von Objekten entfernen. Super einfach.

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

1
Während dieses Code-Snippet die Frage lösen kann, hilft eine Erklärung wirklich dabei, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage in Zukunft für Leser beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
DimaSan

2

Ich kenne die DeleteAllOnSubmit- Methode für jeden Datenkontext, der alle Datensätze in der Abfrage löscht. Es muss eine Optimierung zugrunde liegen, da viele Objekte gelöscht werden. Ich bin mir allerdings nicht sicher.


3
Es wird tatsächlich keine Optimierung durchgeführt. Das generierte SQL listet alle Objekte auf, die Ihrer Abfrage entsprechen, und durchläuft sie dann manuell, um sie zu löschen. Zugegeben, die Iteration findet in der Datenbank statt und nicht in Ihrem Code, aber Sie erstellen immer noch unnötig eine Ergebnismenge, um nur deren Inhalt zu löschen - immer noch weitaus schlimmer als eine einfache "DELETE FROM table WHERE foo = bar", die erstellt wird Keine Ergebnismenge und deckt die Tabelle nur einmal ab.
Benjamin Pollack

2

Ich bin mir nicht sicher, wie effizient es wäre, aber Sie könnten so etwas ausprobieren:

// 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
Das führt immer noch dazu, dass alle Elemente durchlaufen werden, die der Abfrage entsprechen. Dies geschieht lediglich in der Datenbank und nicht in Ihrem Code. Effizienter, aber noch weit von einer idealen Lösung entfernt.
Benjamin Pollack

3
Der einzige andere Weg, den ich mir vorstellen könnte, wäre myDataContext.ExecuteCommand ("DELETE ...");. Auch alles andere als ideal, aber es würde funktionieren.
Scott Anderson

1

Sie könnten einen gespeicherten Prozess schreiben, der das Löschen ausführt, und ihn von LINQ aus aufrufen. Ein satzbasiertes Löschen ist wahrscheinlich insgesamt schneller. Wenn jedoch zu viele Datensätze betroffen sind, können Sperrprobleme auftreten, und Sie benötigen möglicherweise eine Mischung aus Durchlaufen von Datensatzgruppen (möglicherweise 2000 gleichzeitig, die Größe hängt von Ihrem Datenbankdesign ab, 2000 ist jedoch eine Startort, wenn Sie feststellen, dass das satzbasierte Löschen so lange dauert, dass es die andere Verwendung der Tabelle beeinflusst, um das Löschen durchzuführen.


1

Das Löschen von Daten über das Entity Framework basiert auf der Verwendung der DeleteObject-Methode. Sie können diese Methode in der EntityCollection für die zu löschende Entitätsklasse oder im abgeleiteten ObjectContext aufrufen. Hier ist ein einfaches Beispiel:

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();

Das ist aber nicht "Bulk Delete".
Nuzzolilo

1

In diesem Beispiel werden die Datensätze gelöscht, und nacheinander werden sie an die Ergebnismenge angehängt. Anschließend werden sie entfernt. Dann habe ich 1 Änderungen gespeichert.

    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));

Dies ist die schnellste Methode zum Löschen von Datensätzen aus der Datenbank mithilfe von EF


0

Ich würde so etwas tun wie:

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();
    }
}   

Ich glaube nicht, dass es eine Möglichkeit gibt, dies ohne Schleife zu tun, da Entity Framework mit Entities zusammenarbeitet. Meistens bedeutet dies das Sammeln von Objekten.


Sie können auch teilen, was Sie getan haben. Vielen Dank.
G Jeny Ramirez

@G Jeny Ramirez Meine Lösung wurde hinzugefügt.
Demodave

2
@GJennyRamirez auch in Ihrem Beispiel speichern Sie Änderungen mehrmals, die ich denke, dass Sie das aus der foreach-Schleife herausziehen und einmal ausführen können
Demodave
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.