ฉันสามารถตั้งค่าการลบ Cascade ใน Rails ได้หรือไม่


90

ฉันรู้ว่านี่อาจเป็นบนอินเทอร์เน็ตที่ไหนสักแห่ง แต่ฉันไม่พบคำตอบที่นี่ใน Stackoverflow ดังนั้นฉันจึงคิดว่าฉันอาจเพิ่มฐานความรู้ที่นี่เล็กน้อย

ฉันเป็นมือใหม่ของ Ruby and Rails แต่ บริษัท ของฉันกำลังได้รับการลงทุนในเรื่องนี้ดังนั้นฉันจึงพยายามทำความรู้จักกับมันในรายละเอียดเพิ่มเติม

เป็นเรื่องยากสำหรับฉันที่จะเปลี่ยนความคิดในการออกแบบแอปพลิเคชันจาก "โมเดล" แทนที่จะเป็นจากฐานข้อมูลดังนั้นฉันจึงพยายามคิดว่างานออกแบบทั้งหมดที่ฉันทำแบบคลาสสิกจะทำอย่างไรในฐานข้อมูลใน โมเดลรางแทน

ดังนั้นงานล่าสุดที่ฉันมอบให้ตัวเองคือการหาวิธีกำหนดค่าโมเดลฐานข้อมูล Rails เพื่อทำการลบแบบเรียงซ้อน? มีวิธีง่ายๆในการทำเช่นนี้หรือไม่? หรือฉันจะต้องเข้าไปใน MySql แล้วตั้งค่านี้?

คำตอบ:


106

คุณยังสามารถตั้งค่าตัวเลือก: ขึ้นอยู่กับ: delete_all : delete_all จะออกคำสั่ง SQL เดียวเพื่อลบเร็กคอร์ดลูกทั้งหมด เนื่องจากการใช้: delete_all อาจให้ประสิทธิภาพที่ดีขึ้น

has_many :memberships, dependent: :delete_all

8
คำอธิบายของคุณสับสน จะใช้คำสั่ง SQL เพียงคำสั่งเดียว แต่วิธีการทำลายจะไม่ถูกเรียกใช้สำหรับแต่ละแถวลูก คุณต้องใช้ destroy_all สำหรับสิ่งนั้น
John Topley

@ จอห์น - หวังว่าการแก้ไขจะช่วยขจัดความสับสน ขอบคุณที่ชี้ให้เห็น
Mike Breen

27
ตรวจสอบให้แน่ใจว่าคุณเข้าใจความแตกต่างระหว่างการใช้:delete_allและ:destroyสำหรับสิ่งนี้ ทั้งสองจะทำให้เกิดการเป็นสมาชิกเด็ก (1 ระดับสำหรับการลบ [ต้องการการอ้างอิง] และnสำหรับการทำลาย (หากลูกของพวกเขามีการทำลายที่ขึ้นกับกัน)) จะถูกลบออกจากฐานข้อมูล แต่:destroyจะสร้างอินสแตนซ์ของแต่ละออบเจ็กต์ลูกและเรียกใช้การเรียกกลับก่อนในขณะที่:delete_allจะเรียกใช้โดยตรง คำสั่ง SQL DELETE ในฐานข้อมูล :destroyช้ากว่าด้วยเหตุนี้ แต่จะช่วยให้คุณสามารถโทรกลับได้เมื่อบันทึกถูกทำลาย การหลีกเลี่ยง Rails ที่ปลายด้านหนึ่งและการสร้างอินสแตนซ์ n ^ x ที่อาจเกิดขึ้นบนอีกด้านหนึ่ง
jstim

2
ฉันขอแนะนำให้ตั้งค่าคีย์ต่างประเทศของฐานข้อมูลด้วย ด้วยวิธีนี้จะลบบันทึกด้วยการดำเนินการเดียว ดูคำตอบด้านล่างที่ฉันโพสต์
Hendrik

66

ใช่คุณทำได้ถ้าคุณใช้ความสัมพันธ์เช่น has_many คุณก็ทำสิ่งนี้

has_many :memberships, dependent: :destroy

Dan ฉันเดาว่าคำถามต่อไปของฉันคือถ้าฉันเรียกใช้คำสั่ง db migrate จะตั้งค่านั้นใน db จริงหรือ? หรือการเรียงซ้อนถูกจัดการโดยรางอย่างสมบูรณ์?
matt_dev

ใช่มันจัดการโดยราง (ตรวจสอบให้แน่ใจว่าคุณจำเป็นต้องลบทุกแถวที่เกี่ยวข้องจริงๆ)
Stein G. Strindhaug

@Matt - has_many บรรทัดควรอยู่ในคลาสโมเดลของคุณการย้ายข้อมูลจะไม่เพิ่มให้คุณ
Gareth

ฉันชอบโซลูชันนี้เพราะมันใช้งานได้เช่นกันหากโมเดลที่อ้างอิงมีความสัมพันธ์อื่น has_many
tpei

27

ตรงกันข้ามกับคำตอบที่ให้มาฉันขอแนะนำอย่างยิ่งให้ทำเช่นนี้ในระดับฐานข้อมูล ในกรณีที่คุณมีกระบวนการที่แตกต่างกันหรือสภาพแวดล้อมแบบมัลติเธรดอาจเกิดขึ้นได้ว่าระเบียนไม่ได้ถูกลบอย่างถูกต้อง นอกจากนี้คีย์ต่างประเทศของฐานข้อมูลยังช่วยให้สิ่งต่างๆเร็วขึ้นเมื่อลบข้อมูลจำนวนมาก

เช่นเดียวกับในคำตอบที่แนะนำให้ทำสิ่งนี้:

has_many :memberships, dependent: :delete_all

อย่างไรก็ตามอย่าลืมตั้งค่าforeign_keyในการย้ายข้อมูล ด้วยวิธีนี้ฐานข้อมูลจะดูแลการลบบันทึกให้คุณโดยอัตโนมัติ

ในการลบค่าเมื่อสมาชิกถูกลบสมมติว่าคุณมีโมเดลผู้ใช้:

add_foreign_key :users, :memberships, on_delete: :nullify

คุณยังสามารถลบโมเดลทั้งหมดเมื่อใดก็ตามที่สมาชิกถูกลบ

add_foreign_key :users, :memberships, on_delete: :cascade

ฉันสามารถใช้ทั้ง "has_many: Memberships, depend:: delete_all" และ "add_foreign_key: users,: Memberships, on_delete:: cascade" ได้หรือไม่ จะใช้ได้ดีหรือไม่
Rubycon

2
คุณไม่จำเป็นต้องตั้งค่าdelete_allในโมเดลด้วยซ้ำ คีย์นอกจะดูแลการลบทุกอย่างให้คุณในระดับฐานข้อมูลอย่างเหมาะสม
Hendrik

3
ฉันอยากรู้ว่าจะเกิดอะไรขึ้นเมื่อคุณทำทั้งสองอย่าง ดูเหมือนว่ามันไม่น่าจะส่งผลเสีย แต่มีใครเคยมีประสบการณ์แย่ ๆ กับการฝึกทำทั้ง AR และ DB ระดับนี้บ้างไหม?
James Klein

1
ระดับฐานข้อมูลคือสิ่งที่ฉันกำลังมองหา นี่ควรเป็นคำตอบที่ยอมรับได้ในความคิดของฉัน คนอื่นดูเหมือนว่าจะใช้ได้ก็ต่อเมื่อการค้นหาของฉันยึดติดกับการดำเนินการ ActiveRecord มาตรฐาน
Brett Beatty


6

ดูเหมือนว่าปลั๊กอินนี้อาจให้สิ่งที่คุณกำลังมองหาหากคุณต้องการให้การลบแบบเรียงซ้อนสะท้อนในโครงสร้างฐานข้อมูลจริง:

http://www.redhillonrails.org/foreign_key_migrations.html

รูปแบบสำหรับการใช้สิ่งนี้ในการย้ายข้อมูลจะเป็นดังนี้:

create_table :orders do |t|
  t.column :customer_id, :integer, :on_delete => :set_null, :on_update => :cascade
  ...
end

5
ลิงค์นั้นตายไปแล้ว แต่นี่เป็นทางเลือกใหม่: github.com/matthuhiggins/foreigner
gdelfino
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.