392 Stimmen

Wie kann ich mehrere Zeilen in Entity Framework löschen (ohne foreach)

Ich lösche mehrere Elemente aus einer Tabelle mit Entity Framework. Es gibt keinen Fremdschlüssel / übergeordnetes Objekt, so dass ich dies nicht mit OnDeleteCascade behandeln kann.

Im Moment mache ich das:

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

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

Es funktioniert, aber das foreach stört mich. Ich verwende EF4, aber ich möchte kein SQL ausführen. Ich möchte nur sicherstellen, dass ich nichts verpasse - das ist so gut wie es geht, richtig? Ich kann es mit einer Erweiterungsmethode oder einem Helfer abstrahieren, aber irgendwo werden wir immer noch ein foreach ausführen, richtig?

786voto

Kyle Punkte 30571

EntityFramework 6 hat dies ein wenig einfacher gemacht mit .RemoveRange() .

Beispiel:

db.People.RemoveRange(db.People.Where(x => x.State == "CA"));
db.SaveChanges();

81voto

Vlad Bezden Punkte 71128
using (var context = new DatabaseEntities())
{
    context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}

Zusatz: Um eine Liste von IDs zu unterstützen, können Sie schreiben

var listOfIds = String.Join(',',customerIds.Select(id => $"'{id}'").ToList());
var sql= $@"DELETE  [YOURTABLE] WHERE CustomerID in ({listOfIds})";

Hinweis: Wenn CustomerID eine Zeichenkette ist, sollten Sie doppelt auf potenzielle SQL-Injection-Risiken prüfen, bei ganzzahligen CustomerID ist es sicher.

71voto

Klaus Byskov Pedersen Punkte 111081

besser geht's nicht, oder? Ich kann es mit einer Erweiterung abstrahieren Methode oder einem Helfer abstrahieren, aber irgendwo werden wir immer noch eine foreach, richtig?

Nun, ja, aber man kann daraus einen Zweizeiler machen:

context.Widgets.Where(w => w.WidgetId == widgetId)
               .ToList().ForEach(context.Widgets.DeleteObject);
context.SaveChanges();

63voto

Thanh Nguyen Punkte 1006

Ich weiß, dass es ziemlich spät ist, aber falls jemand eine einfache Lösung braucht, kann man auch die Where-Klausel mit einbeziehen:

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    string selectSql = db.Set<T>().Where(filter).ToString();
    string fromWhere = selectSql.Substring(selectSql.IndexOf("FROM"));
    string deleteSql = "DELETE [Extent1] " + fromWhere;
    db.Database.ExecuteSqlCommand(deleteSql);
}

Hinweis: nur mit MSSQL2008 getestet.

Aktualisierung:

Die obige Lösung funktioniert nicht, wenn EF eine Sql-Anweisung mit Parameter Hier ist das Update für EF5 :

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    var query = db.Set<T>().Where(filter);

    string selectSql = query.ToString();
    string deleteSql = "DELETE [Extent1] " + selectSql.Substring(selectSql.IndexOf("FROM"));

    var internalQuery = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_internalQuery").Select(field => field.GetValue(query)).First();
    var objectQuery = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_objectQuery").Select(field => field.GetValue(internalQuery)).First() as ObjectQuery;
    var parameters = objectQuery.Parameters.Select(p => new SqlParameter(p.Name, p.Value)).ToArray();

    db.Database.ExecuteSqlCommand(deleteSql, parameters);
}

Es erfordert ein wenig Nachdenken, funktioniert aber gut.

52voto

Alex James Punkte 20783

Wenn Sie SQL nicht direkt ausführen wollen, ist der Aufruf von DeleteObject in einer Schleife das Beste, was Sie heute tun können.

Sie können jedoch SQL ausführen und es dennoch über eine Erweiterungsmethode vollständig für allgemeine Zwecke einsetzen, indem Sie den von mir beschriebenen Ansatz verwenden aquí .

Diese Antwort galt allerdings für 3,5. Für 4.0 würde ich wahrscheinlich die neue ExecuteStoreCommand API unter der Haube verwenden, anstatt auf die StoreConnection zurückzugreifen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X