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?

Saggex
quelle

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.

Gemeinschaft
quelle
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 .

Taimoor Changaiz
quelle
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.

Nickcen
quelle
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.

jamesc
quelle
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.

Severin
quelle
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]]
David Zhang
quelle