delete_all vs destroy_all?


193

Bir tablodan kayıtları silmek için en iyi yaklaşımı arıyorum. Örneğin, kullanıcı kimliği birçok tabloda olan bir kullanıcı var. Bu kullanıcıyı ve tüm tablolarda kimliğini içeren her kaydı silmek istiyorum.

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Bu çalışır ve kullanıcının tüm tablolardan tüm referansları kaldırır, ama destroy_allçok işlem ağır olduğunu duydum , bu yüzden denedim delete_all. Yalnızca kendi kullanıcı tablosundan kullanıcıyı kaldırır ve iddiğer tüm tablolardan null yapılır, ancak kayıtların içinde olduğu gibi kalır. Birisi böyle bir görevi yerine getirmek için doğru sürecin ne olduğunu paylaşabilir mi?

Tüm ilişkili nesneler üzerinde işlevi destroy_allçağırdığını görüyorum destroyama sadece doğru yaklaşımı onaylamak istiyorum.

Yanıtlar:


244

Haklısın. Kullanıcı'yı ve ilişkili tüm nesneleri silmek istiyorsanız -> destroy_all Ancak, yalnızca ilişkili tüm nesneleri bastırmadan Kullanıcıyı silmek istiyorsanız ->delete_all

Bu mesaja göre: Raylar: bağımlı =>: yok VS: bağımlı =>: delete_all

  • destroy/ destroy_all: İlişkili nesneler, destroy yöntemini çağırarak bu nesnenin yanında imha edilir
  • delete/ delete_all: İlişkili tüm nesneler, kendi: destroy yöntemini çağırmadan hemen imha edilir

80
Ayrıca not edilmelidir ki 1) kullanırken geri çağrılar çağrılmaz delete_allve 2) destroy_alltüm kayıtları başlatır ve birer birer yok eder, bu nedenle çok büyük bir veri kümesinde bu acı verici bir şekilde yavaş olabilir.
Dylan Markow

modelde bir before_destroy yöntemi çalıştırıyorum varsayalım - eğer delete_all kullanırsanız bu yöntem çalışmaz? İkincisi, modelimde bir before_delete yöntemi kullanırsam, raylar konsolunda delete veya delete_all çalıştırdığımda bu çalışır mı?
BKSpurgeon

23

delete_all tek bir SQL DELETE deyimidir ve başka bir şey değildir. destroy_all, şu koşulların eşleşen tüm sonuçlarında destroy () öğesini çağırır (varsa) (en azından NUM_OF_RESULTS SQL ifadesi olabilir).

Büyük veri kümesinde destroy_all () gibi sert bir şey yapmak zorunda kalırsanız, muhtemelen uygulamadan yapmaz ve dikkatli bir şekilde elle idare etmezdim. Veri kümesi yeterince küçükse, çok fazla incitmezsiniz.


16

Gerçeği önlemek için destroy_allTüm kayıtları başlatan ve birer birer yok edenlerden , doğrudan model sınıfından kullanabilirsiniz.

Bunun yerine:

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Yapabilirsin :

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Sonuç, ilişkili tüm kayıtları yok etmek için kullanılan bir sorgudur


1
İlişkili kayıtlarda yok etme geri çağrılarını mı arayacak yoksa buna UsageIndex.destroy_alleşdeğer UsageIntex.delete_allmi?
Magne

UsageIndex.destroy_allraylar 3
fabriciofreitag

1

Bazı durumlarda ilişkili kayıtları el ile silme ihtiyacını hafifletebilecek küçük bir taş yaptım .

Bu değerli taş, ActiveRecord ilişkilendirmeleri için yeni bir seçenek ekler:

bağımlı:: delete_recursively

Bir kaydı yok ettiğinizde, bu seçeneği kullanarak ilişkilendirilmiş tüm kayıtlar, herhangi bir örnek oluşturmadan yinelemeli olarak (örn. Modeller arasında) silinir.

Tüm bağımlı:: delete veya bağımlı:: delete_all gibi, bu yeni seçeneğin bağımlı kayıtların çevresinde / öncesinde / sonrasında geri çağrılarını tetiklemediğini unutmayın.

Ancak, bağımlı olmak mümkündür:: aksi takdirde bağımlı olan bir model zinciri içinde herhangi bir yerde ilişkilendirmeleri yok etmek:: delete_recursively. : Destroy seçeneği normalde yukarı veya aşağı herhangi bir yerde çalışır, ilgili tüm kayıtları başlatır ve imha eder ve böylece geri aramalarını tetikler.


Bu fantastik! Acaba neden daha fazla insanın github'da izlemediği / yıldız göstermediği / çatallanmadığı .. hala iyi çalışıyor mu?
Magne

@Magne Teşekkürler! Çalışıyor olmalı. Testler Ruby 2.4.1 ve Rails 5.1.1 üzerinde yapılır. Şimdiye kadar sadece özel olarak kullandım ve büyük üretim uygulamalarında kullanmadım, bu nedenle büyük sürüm "0", ancak hiçbir sorun fark etmedim. Aynı zamanda oldukça basit, bu yüzden iyi olmalı.
Janosch

Güzel. :) Ruby 2.3.1 ve 'raylar', '~> 4.1.14' üzerinde bir proje yürütüyorum ve ne yazık ki diğer taşlar nedeniyle activerecord'a (~> 4.1.0) güvenmek zorunda kalıyorum. Delete_recursively 0.9.0 için çözülmüş olduğunu görüyorum. Activerecord 4.1 ile çalışacak daha eski bir sürümü var mı? Github'daki yayınlar sekmesinde herhangi bir şey bulamadım.
Magne

1
@Magne aslında 4.1.14 kadar düşük activerecord için çalışıyor ve rahat bir bağımlılık ile gem sürüm 1.0.0 yayımladı bulundu. Rails, 4.1 şubesinin artık güvenlik güncellemelerini almadığını unutmayın.
Janosch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.