So löschen Sie ein Objekt anhand der ID mit dem Entity Framework

105

Es scheint mir, dass ich ein Objekt abrufen muss, bevor ich es mit dem Entity Framework wie unten lösche

var customer = context.Customers.First(c => c.Id == 1);

context.DeleteObject(customer);

context.Savechanges();

Ich muss also zweimal auf die Datenbank klicken. Gibt es einen einfacheren Weg?

Jeff
quelle
j.mp/f0x0Bh ist Ihre Antwort. Dies ist eine schöne und generische Methode
BritishDeveloper

Antworten:

93

In Entity Framework 6 lautet die Löschaktion Remove. Hier ist ein Beispiel

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();
dwkd
quelle
16
Warum Attach? Warum nicht einfach Removeund SaveChanges?
Runeks
3
Sie müssen Ihre Entität im Kontext anhängen, da sonst beim Entfernen eine Fehlermeldung angezeigt wird. EF kann Entitäten nur in diesem Zusammenhang entfernen
Pierre-Luc
3
@runeks Gemäß dem Handbuch muss die Entität im Kontext vorhanden sein, bevor der Entfernungsvorgang ausgeführt werden kann. Siehe hier docs.microsoft.com/en-us/dotnet/api/…
dwkd
1
Ich habe
Attach
58

Das gleiche wie @Nix mit einer kleinen Änderung, die stark eingegeben werden muss:

Wenn Sie nicht danach fragen möchten, erstellen Sie einfach eine Entität und löschen Sie sie.

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();
Sawan
quelle
7
Nicht perfekt, da es eine Ausnahme auslöst, wenn das Objekt fehlt: "DbUpdateConcurrencyException: Das Speichern der Anweisung zum Aktualisieren, Einfügen oder Löschen hat eine unerwartete Anzahl von Zeilen (0) beeinflusst." Ich möchte, dass es dies ignoriert, wie es eine DELETE-Anweisung tun würde.
Dunc
Entschuldigung, dies führt zu einer Validierung, die nicht immer benötigt und erwartet wird!
Hamed Zakery Miab
32

Ähnliche Frage hier .

Mit Entity Framework gibt es EntityFramework-Plus (Erweiterungsbibliothek).
Verfügbar bei NuGet. Dann können Sie etwas schreiben wie:

// DELETE all users which has been inactive for 2 years
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
     .Delete();

Es ist auch nützlich für Massenlöschungen.

Acarlon
quelle
36
Es widerspricht dem Grund, dass dies derzeit nicht Teil der EF-Kernbibliothek ist.
Nathanchere
1
@ FerretallicA - vereinbart.
Acarlon
2
Diese Methode ist veraltet. Verwenden Sie: context.Users.Where (user => user.Id == id) .Delete ();
Manuel
Es funktioniert nicht mit Azure SQL DataWarehouse aufgrund des Fehlers "Eine FROM-Klausel wird derzeit in einer DELETE-Anweisung nicht unterstützt." Aber das rohe SQL wie in Joniks Antwort funktioniert.
Michael Freidgeim
1
Wird context.SaveChanges () benötigt?
Tomas Kubes
23

Wenn Sie nicht danach fragen möchten, erstellen Sie einfach eine Entität und löschen Sie sie.

Customer customer  = new Customer() {  Id = 1   } ; 
context.AttachTo("Customers", customer);
context.DeleteObject(customer);
context.Savechanges();
Nix
quelle
6

Ich verwende den folgenden Code in einem meiner Projekte:

    using (var _context = new DBContext(new DbContextOptions<DBContext>()))
    {
        try
        {
            _context.MyItems.Remove(new MyItem() { MyItemId = id });
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            if (!_context.MyItems.Any(i => i.MyItemId == id))
            {
                return NotFound();
            }
            else
            {
                throw ex;
            }
        }
    }

Auf diese Weise wird die Datenbank nur zweimal abgefragt, wenn beim Versuch, das Element mit der angegebenen ID zu entfernen, eine Ausnahme auftritt. Wenn das Element dann nicht gefunden wird, wird eine aussagekräftige Nachricht zurückgegeben. Andernfalls wird die Ausnahme nur zurückgeworfen (Sie können dies auf eine Weise behandeln, die besser zu Ihrem Fall passt, indem Sie verschiedene Catch-Blöcke für verschiedene Ausnahmetypen verwenden, weitere benutzerdefinierte Prüfungen mit if-Blöcken hinzufügen usw.).

[Ich verwende diesen Code in einem MVC .Net Core / .Net Core-Projekt mit Entity Framework Core.]

Demonicdaron
quelle
2

Raw SQL-Abfrage ist wohl der schnellste Weg

public void DeleteCustomer(int id)
{
   using (var context = new Context())
   {
      const string query = "DELETE FROM [dbo].[Customers] WHERE [id]={0}";
      var rows = context.Database.ExecuteSqlCommand(query,id);
      // rows >= 1 - count of deleted rows,
      // rows = 0 - nothing to delete.
   }
}
Jonik
quelle
19
Dies macht den Zweck der Verwendung stark typisierter Objektfunktionen in EF zunichte.
LawMan
4
Dies gefährdet das EF-Identitätsgeld. Danach wird EF Ihre gelöschte Entität weiterhin an Sie zurücksenden.
Epox
1
Es funktioniert mit Azure SQL DataWarehouse, wenn andere Lösungen dies nicht tun.
Michael Freidgeim
1
Wenn Sie dies tun, können Sie auch kein ORM verwenden. Ich stelle mir vor, dass dies den EF-Cache gefährden würde.
Sturm Müller
Dieser Stil ist anfällig für SQL Injection-Angriffe. In diesem speziellen Beispiel sind Sie geschützt, da die Variable eine Ganzzahl ist. Verwenden Sie dieses Muster jedoch niemals mit einer Zeichenfolgenvariablen.
Thelem
2

Die Antwort von dwkd funktionierte hauptsächlich für mich im Entity Framework-Kern, außer als ich diese Ausnahme sah:

InvalidOperationException: Die Instanz des Entitätstyps 'Kunde' kann nicht verfolgt werden, da bereits eine andere Instanz mit demselben Schlüsselwert für {'ID'} verfolgt wird. Stellen Sie beim Anhängen vorhandener Entitäten sicher, dass nur eine Entitätsinstanz mit einem bestimmten Schlüsselwert angehängt ist. Verwenden Sie 'DbContextOptionsBuilder.EnableSensitiveDataLogging', um die widersprüchlichen Schlüsselwerte anzuzeigen.

Um die Ausnahme zu vermeiden, habe ich den Code aktualisiert:

Customer customer = context.Customers.Local.First(c => c.Id == id);
if (customer == null) {
    customer = new Customer () { Id = id };
    context.Customers.Attach(customer);
}
context.Customers.Remove(customer);
context.SaveChanges();
Jeffrey Rennie
quelle
1

Eine kleinere Version (im Vergleich zu früheren):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();
Luis Gouveia
quelle
Bitte geben Sie einen Kontext zu diesem Code-Snippet und möglicherweise eine Erklärung dessen, was es besser macht als die anderen Antworten, die im letzten Jahrzehnt hinterlassen wurden.
miken32
1

Diese Antwort stammt aus Scott Allens Kurs mit dem Titel ASP.NET MVC 5 Fundamentals. Ich dachte, ich würde teilen, weil ich denke, dass es etwas einfacher und intuitiver ist als jede der Antworten hier bereits. Beachten Sie auch, dass die Suchmethode laut Scott Allen und anderen von mir durchgeführten Schulungen eine optimierte Methode zum Abrufen einer Ressource aus einer Datenbank ist, die Caching verwenden kann, wenn sie bereits abgerufen wurde. In diesem Code bezieht sich die Sammlung auf ein DBSet von Objekten. Objekt kann ein beliebiger generischer Objekttyp sein.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
andy_coder
quelle