ความแตกต่างระหว่าง Destroy และ Delete


210

อะไรคือความแตกต่างระหว่าง

@model.destroy และ @model.delete

ตัวอย่างเช่น:

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

มันสำคัญจริงๆถ้าฉันใช้อันใดอันหนึ่ง?

คำตอบ:


289

โดยทั่วไปdestroyจะเรียกใช้การเรียกกลับใด ๆ ในรูปแบบในขณะที่deleteไม่

จากRails API :

  • ActiveRecord::Persistence.delete

    ลบเร็กคอร์ดในฐานข้อมูลและตรึงอินสแตนซ์นี้เพื่อสะท้อนว่าไม่ควรทำการเปลี่ยนแปลง (เนื่องจากไม่สามารถคงอยู่ได้) ส่งคืนอินสแตนซ์แช่แข็ง

    แถวนั้นจะถูกลบออกโดยใช้คำสั่ง SQL DELETE บนคีย์หลักของเรกคอร์ดและจะไม่มีการดำเนินการเรียกกลับ

    ในการบังคับใช้การเรียกกลับ before_destroy และ after_destroy ของวัตถุหรือตัวเลือกการเชื่อมโยงใด ๆ ที่ขึ้นอยู่กับใช้ #destroy

  • ActiveRecord::Persistence.destroy

    ลบเร็กคอร์ดในฐานข้อมูลและตรึงอินสแตนซ์นี้เพื่อสะท้อนว่าไม่ควรทำการเปลี่ยนแปลง (เนื่องจากไม่สามารถคงอยู่ได้)

    มีชุดของการโทรกลับที่เกี่ยวข้องกับการทำลาย ถ้า before_destroy callback return false การกระทำถูกยกเลิกและ destroy ส่งกลับ false ดู ActiveRecord :: การเรียกกลับสำหรับรายละเอียดเพิ่มเติม


สวัสดี @ user740584 - ขอบคุณสำหรับคำตอบของคุณ คุณหมายถึงอะไรโดย "เรียกใช้การเรียกกลับในรูปแบบใด ๆ "
BKSpurgeon

3
@BKSpurgeon เขาหมายถึง ActiveRecord :: Callbacks: api.rubyonrails.org/classes/ActiveRecord/Callbacks.html การโทรกลับหนึ่งครั้งนั้นmodel#before_destroyสามารถใช้เพื่อหยุดการdestroy()โทรสุดท้ายภายใต้เงื่อนไขบางประการ
ทอดด์

102

delete จะลบระเบียนวัตถุปัจจุบันออกจากฐานข้อมูลเท่านั้น แต่จะไม่ลบระเบียนลูกที่เกี่ยวข้องออกจากฐานข้อมูล

destroy จะลบเร็กคอร์ดอ็อบเจ็กต์ปัจจุบันออกจาก db และรวมถึงชายด์เร็กคอร์ดที่เชื่อมโยงจาก db

การใช้งานของพวกเขาสำคัญมาก:

หากวัตถุหลักหลาย ๆ อันของคุณใช้วัตถุลูกร่วมกันการเรียกdestroyใช้วัตถุแม่เฉพาะจะลบวัตถุลูกที่ใช้ร่วมกันระหว่างผู้ปกครองหลายคน


5
คำตอบที่ยอดเยี่ยม ขอบคุณ. ฉันจะเพิ่มคำศัพท์ตามที่ฉันเข้าใจว่าเด็ก ๆ "ถูกฆ่า" โหดร้ายทารุณ
BKSpurgeon

ในกรณีส่วนใหญ่ในการผลิตคุณต้องการใช้ 'ทำลาย'
Outside_Box

ไม่จำเป็น
Taimoor Changaiz

ฉันคิดว่าคำที่คุณควรใช้destroyเป็นลูกหลานไม่ใช่เด็ก : ตามเอกสารอธิบายทำลาย "สร้างวัตถุใหม่จากแอตทริบิวต์แล้วเรียกใช้ทำลายมัน" rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy
Marco Lackovic

12

เมื่อคุณเรียกใช้destroyหรือdestroy_allบนActiveRecordวัตถุActiveRecordกระบวนการ 'ทำลาย' ถูกเริ่มต้นมันจะวิเคราะห์คลาสที่คุณกำลังลบมันจะกำหนดสิ่งที่ควรทำสำหรับการอ้างอิงการเรียกใช้ผ่านการตรวจสอบความถูกต้อง ฯลฯ

เมื่อคุณเรียกใช้deleteหรือdelete_allบนวัตถุActiveRecordเพียงพยายามเรียกใช้DELETE FROM tablename WHERE conditionsแบบสอบถามกับ db โดยไม่ActiveRecordต้องทำงานระดับอื่น


4

ใช่มีความแตกต่างที่สำคัญระหว่างสองวิธีใช้ delete_all ถ้าคุณต้องการลบระเบียนอย่างรวดเร็วโดยไม่ต้องเรียกแบบจำลองการโทรกลับ

หากคุณสนใจการโทรกลับโมเดลของคุณให้ใช้ destroy_all

จากเอกสารอย่างเป็นทางการ

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

destroy_all (เงื่อนไข = ไม่มี) สาธารณะ

ทำลายเงื่อนไขการจับคู่ระเบียนโดยสร้างอินสแตนซ์แต่ละระเบียนและเรียกใช้วิธีทำลาย การเรียกกลับของวัตถุแต่ละรายการจะดำเนินการ (รวมถึง: ตัวเลือกการเชื่อมโยงที่ต้องพึ่งพาและวิธีการสังเกตการณ์ before_destroy / after_destroy) ส่งคืนชุดของวัตถุที่ถูกทำลาย แต่ละรายการจะถูกแช่แข็งเพื่อสะท้อนว่าไม่ควรทำการเปลี่ยนแปลง (เนื่องจากไม่สามารถยืนยันได้)

หมายเหตุ: การสร้างอินสแตนซ์การเรียกกลับและการลบแต่ละระเบียนอาจใช้เวลานานเมื่อคุณลบหลาย ๆ ระเบียนในคราวเดียว มันสร้างแบบสอบถาม SQL DELETE อย่างน้อยหนึ่งรายการต่อเร็กคอร์ด (หรืออาจมากกว่านั้นเพื่อบังคับใช้การเรียกกลับของคุณ) หากคุณต้องการลบหลายแถวอย่างรวดเร็วโดยไม่ต้องกังวลกับการเชื่อมโยงหรือการโทรกลับให้ใช้ delete_all แทน


2

โดยทั่วไป "ลบ" ส่งแบบสอบถามโดยตรงไปยังฐานข้อมูลเพื่อลบบันทึก ในกรณีดังกล่าว Rails ไม่ทราบว่ามีแอตทริบิวต์ใดบ้างในบันทึกการลบหรือหากมีการเรียกกลับ (เช่นbefore_destroy)

วิธีการ "ทำลาย" ใช้รหัสผ่านดึงรูปแบบจากฐานข้อมูลโดยใช้วิธี "ค้นหา" จากนั้นเรียกใช้ทำลายที่ ซึ่งหมายความว่ามีการเรียกใช้การเรียกกลับ

คุณต้องการใช้ "ลบ" หากคุณไม่ต้องการให้มีการเรียกใช้การเรียกกลับหรือคุณต้องการประสิทธิภาพที่ดีขึ้น มิฉะนั้น (และส่วนใหญ่) คุณจะต้องการใช้ "ทำลาย"


2

มีคำตอบมากมายอยู่แล้ว ต้องการที่จะเพิ่มขึ้นอีกเล็กน้อย

เอกสาร :

สำหรับ has_many ทำลายและ destroy_all มักจะเรียกวิธีทำลายของบันทึก (s) ที่ถูกลบเพื่อให้เรียกใช้การเรียกกลับ อย่างไรก็ตามการลบและ delete_all จะทำการลบอย่างใดอย่างหนึ่งตามกลยุทธ์ที่ระบุโดยตัวเลือก: dependent หรือหากไม่ได้รับ: ขึ้นอยู่กับตัวเลือกแล้วมันจะเป็นไปตามกลยุทธ์เริ่มต้น กลยุทธ์เริ่มต้นคือการไม่ทำอะไรเลย (ปล่อยปุ่มต่างประเทศไว้กับชุดรหัสผู้ปกครอง) ยกเว้น has_many: ถึงโดยที่กลยุทธ์เริ่มต้นคือ delete_all (ลบระเบียนเข้าร่วมโดยไม่เรียกใช้การเรียกกลับ)

deleteverbage ทำงานแตกต่างกันสำหรับการและActiveRecord::Association.has_many ActiveRecord::BaseสำหรับหลังการลบจะดำเนินการSQL DELETEและข้ามการตรวจสอบ / เรียกกลับทั้งหมด อดีตจะถูกดำเนินการตาม:dependentตัวเลือกที่ส่งผ่านไปยังสมาคม อย่างไรก็ตามในระหว่างการทดสอบฉันพบผลข้างเคียงต่อไปนี้ที่มีการเรียกกลับมาเฉพาะdeleteและไม่delete_all

dependent: :destroy ตัวอย่าง:

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]]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.