Unterschied zwischen Zerstören und Löschen


210

Was ist der Unterschied zwischen

@model.destroy und @model.delete

Beispielsweise:

Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all

Ist es wirklich wichtig, ob ich das eine oder das andere benutze?

Antworten:


289

Grundsätzlich werden destroykeine Rückrufe auf dem Modell ausgeführt, während deletedies nicht der Fall ist.

Aus der Rails-API :

  • ActiveRecord::Persistence.delete

    Löscht den Datensatz in der Datenbank und friert diese Instanz ein, um anzuzeigen, dass keine Änderungen vorgenommen werden sollten (da sie nicht beibehalten werden können). Gibt die eingefrorene Instanz zurück.

    Die Zeile wird einfach mit einer SQL DELETE-Anweisung auf dem Primärschlüssel des Datensatzes entfernt, und es werden keine Rückrufe ausgeführt.

    Verwenden Sie #destroy, um die Rückrufe vor_destroy und after_destroy des Objekts oder andere: abhängige Zuordnungsoptionen zu erzwingen.

  • ActiveRecord::Persistence.destroy

    Löscht den Datensatz in der Datenbank und friert diese Instanz ein, um anzuzeigen, dass keine Änderungen vorgenommen werden sollten (da sie nicht beibehalten werden können).

    Es gibt eine Reihe von Rückrufen, die mit Zerstörung verbunden sind. Wenn der Rückruf before_destroy false zurückgibt, wird die Aktion abgebrochen und destroy gibt false zurück. Weitere Informationen finden Sie unter ActiveRecord :: Callbacks.


Hallo @ user740584 - danke für deine Antwort. Was meinst du mit "führt Rückrufe auf dem Modell aus"?
BKSpurgeon

3
@BKSpurgeon meint er ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html . Ein solcher Rückruf model#before_destroykann verwendet werden, um den letzten destroy()Anruf unter bestimmten Bedingungen anzuhalten.
Todd

102

delete löscht nur den aktuellen Objektdatensatz aus der Datenbank, nicht jedoch die zugehörigen untergeordneten Datensätze aus der Datenbank.

destroy löscht den aktuellen Objektdatensatz aus der Datenbank und den zugehörigen untergeordneten Datensatz aus der Datenbank.

Ihre Verwendung ist wirklich wichtig:

Wenn mehrere übergeordnete Objekte gemeinsame untergeordnete Objekte verwenden, werden durch Aufrufen eines destroybestimmten übergeordneten Objekts untergeordnete Objekte gelöscht, die von mehreren übergeordneten Objekten gemeinsam genutzt werden .


5
Geniale Antwort. Danke. Ich würde hinzufügen, dass die Terminologie, wie ich sie verstehe, ist, dass die Kinder "getötet" werden. brutaler Kindsmord.
BKSpurgeon

In den meisten Fällen in der Produktion möchten Sie 'destroy'
Outside_Box

Nein, das ist nicht nötig.
Taimoor Changaiz

Ich denke, das Wort, für das Sie verwenden sollten, destroysind Nachkommen , keine Kinder : Gemäß der Dokumentation erstellt destroy "ein neues Objekt aus den Attributen und ruft dann destroy darauf auf". rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

Wenn Sie ein Objekt aufrufen destroyoder destroy_allein ActiveRecordObjekt aufrufen , wird der ActiveRecordZerstörungsprozess eingeleitet, die zu löschende Klasse analysiert, festgelegt, was für Abhängigkeiten getan werden soll, Überprüfungen durchlaufen usw.

Wenn Sie ein Objekt aufrufen deleteoder delete_allbearbeiten, wird ActiveRecordlediglich versucht, die DELETE FROM tablename WHERE conditionsAbfrage für die Datenbank auszuführen , ohne dass ActiveRecordAufgaben auf anderer Ebene ausgeführt werden.


4

Ja, es gibt einen großen Unterschied zwischen den beiden Methoden. Verwenden Sie delete_all, wenn Datensätze schnell gelöscht werden sollen, ohne dass Modellrückrufe aufgerufen werden

Wenn Sie sich für Rückrufe Ihrer Modelle interessieren, verwenden Sie destroy_all

Aus den offiziellen Dokumenten

http://apidock.com/rails/ActiveRecord/Base/destroy_all/class

destroy_all (Bedingungen = Null) public

Zerstört die übereinstimmenden Bedingungen der Datensätze, indem jeder Datensatz instanziiert und seine Zerstörungsmethode aufgerufen wird. Die Rückrufe jedes Objekts werden ausgeführt (einschließlich: abhängiger Zuordnungsoptionen und before_destroy / after_destroy Observer-Methoden). Gibt die Sammlung von Objekten zurück, die zerstört wurden. Jedes wird eingefroren, um zu berücksichtigen, dass keine Änderungen vorgenommen werden sollten (da sie nicht beibehalten werden können).

Hinweis: Das Instanziieren, Ausführen von Rückrufen und Löschen jedes Datensatzes kann zeitaufwändig sein, wenn Sie mehrere Datensätze gleichzeitig entfernen. Es generiert mindestens eine SQL DELETE-Abfrage pro Datensatz (oder möglicherweise mehr, um Ihre Rückrufe zu erzwingen). Wenn Sie viele Zeilen schnell löschen möchten, ohne Rücksicht auf ihre Zuordnungen oder Rückrufe, verwenden Sie stattdessen delete_all.


2

Grundsätzlich sendet "Löschen" eine Abfrage direkt an die Datenbank, um den Datensatz zu löschen. In diesem Fall weiß Rails nicht, welche Attribute in dem zu löschenden Datensatz enthalten sind oder ob Rückrufe (z. B. before_destroy) vorliegen .

Die "destroy" -Methode nimmt die übergebene ID, ruft das Modell mit der "find" -Methode aus der Datenbank ab und ruft dann destroy auf. Dies bedeutet, dass die Rückrufe ausgelöst werden.

Sie möchten "Löschen" verwenden, wenn Sie nicht möchten, dass die Rückrufe ausgelöst werden, oder wenn Sie eine bessere Leistung wünschen. Andernfalls (und meistens) möchten Sie "destroy" verwenden.


2

Viele Antworten schon; wollte mit etwas mehr weitermachen.

docs :

Bei has_many rufen destroy und destroy_all immer die destroy-Methode der zu entfernenden Datensätze auf, damit Rückrufe ausgeführt werden. Löschen und delete_all führen das Löschen jedoch entweder gemäß der durch die Option: abhängige Strategie angegebenen Strategie durch, oder wenn keine: abhängige Option angegeben ist, folgt es der Standardstrategie. Die Standardstrategie besteht darin, nichts zu tun (die Fremdschlüssel mit den übergeordneten IDs belassen), außer has_many: through, wobei die Standardstrategie delete_all lautet (Löschen der Join-Datensätze, ohne deren Rückrufe auszuführen).

Das deleteVerb funktioniert anders für ActiveRecord::Association.has_manyund ActiveRecord::Base. Für letzteres führt delete SQL DELETEalle Überprüfungen / Rückrufe aus und umgeht sie. Ersteres wird basierend auf der :dependentan den Verein übergebenen Option ausgeführt . Beim Testen stellte ich jedoch den folgenden Nebeneffekt fest, bei dem Rückrufe nur ausgeführt wurden deleteund nichtdelete_all

dependent: :destroy Beispiel:

class Parent < ApplicationRecord
   has_many :children,
     before_remove: -> (_) { puts "before_remove callback" },
     dependent: :destroy
end

class Child < ApplicationRecord
   belongs_to :parent

   before_destroy -> { puts "before_destroy callback" }
end

> child.delete                            # Ran without callbacks
Child Destroy (99.6ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 21]]

> parent.children.delete(other_child)     # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms)  DELETE FROM "children" WHERE "children"."id" = $1  [["id", 22]]

> parent.children.delete_all              # Ran without callbacks
Child Destroy (1.0ms)  DELETE FROM "children" WHERE "children"."parent_id" = $1  [["parent_id", 1]]
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.