Ruby on rails 是否可以批量级联活动记录删除?

Ruby on rails 是否可以批量级联活动记录删除?,ruby-on-rails,rails-activerecord,cascade,Ruby On Rails,Rails Activerecord,Cascade,我有很多数据要删除,因此我使用delete/delete\u all而不是destroy,通过外键上的cascade(on\u delete::cascade) 我想删除一个父活动记录,它有两个包含许多行的“子表”。这些子表中的一些也有几个子表。出于这个原因,我在外键上添加了cascade,这样我只需要调用parent.delete就可以触发删除parent的所有子级和孙子级 我想将delete/delete_all与活动记录批次相结合,但由于只有一个父级,我不确定如何以整洁的方式组合批次和级联

我有很多数据要删除,因此我使用delete/delete\u all而不是destroy,通过外键上的cascade(
on\u delete::cascade

我想删除一个父活动记录,它有两个包含许多行的“子表”。这些子表中的一些也有几个子表。出于这个原因,我在外键上添加了cascade,这样我只需要调用parent.delete就可以触发删除parent的所有子级和孙子级

我想将delete/delete_all与活动记录批次相结合,但由于只有一个父级,我不确定如何以整洁的方式组合批次和级联删除

一种选择是显式批量删除子代和孙子代,例如

parent.children_x.find_each do |child_x|
  child_x.grand_children_y.in_batches do |grand_child_y_batch|
    grand_child_y_batch.delete_all        
  end
  child_x.delete        
end
parent.children_z.in_batches do |child_batch|
  child_batch.delete_all
end
...etc...
但是,如果有一种更隐晦的方式,允许我只对父代调用delete,并批量删除子代和孙子代,那将是更可取的,例如

parent.cascade_in_batches do |parent_batch|
  parent_batch.delete_all #This batch deletes all children and grand children
end
我看到在父项上没有
in_batches
,因为父项只是一个实体,所以看起来只有在上面的第一个示例中明确地批量删除时才有可能

谢谢


-Louise

您只需将外键设置为cascade,Postgres将负责删除所有外键。因为这是在数据库层上实现的,所以无论您如何触发从Rails中删除都无关紧要

class CreateCountries < ActiveRecord::Migration[6.0]
  def change
    create_table :countries do |t|
      t.string :name
      t.timestamps
    end
  end
end

class CreateStates < ActiveRecord::Migration[6.0]
  def change
    create_table :states do |t|
      t.string :name
      t.belongs_to :country, null: false, foreign_key: {on_delete: :cascade}
      t.timestamps
    end
  end
end

class CreateCities < ActiveRecord::Migration[6.0]
  def change
    create_table :cities do |t|
      t.string :name
      t.belongs_to :state, null: false, foreign_key: {on_delete: :cascade}
      t.timestamps
    end
  end
end
如果您使用的是
。这里的每个\u与\u批处理
或非批处理都是不相关的。任何创建
DELETE FROM countries
查询的操作都将触发该数据库触发器。除非您确实需要评估是否应该在Rails中删除每个父级,否则您应该能够执行以下操作:

Country.where(evil: true).delete_all

这将比
高效得多。查找每个
,因为您只需执行一个SQL查询。如果您对记录进行迭代,您将对每行执行一个
DELETE FROM coutries,其中id=?
查询,并且由于其阻塞轨道必须等待到数据库的往返行程。

Ah ok-因此,请确保我理解:parent.DELETE触发的级联删除将为每个表生成一个SQL DELETE语句,子级和父级表“从X中删除,其中在(…)”,这意味着在这个场景中不需要批处理功能?在您编写时,如果您想使用destroy,或者如果您想使用对象执行一些逻辑来确定是否应该删除该对象,那么只需要使用批处理功能?不,您仍然没有得到它。在规范中的示例中,当您调用
country.delete
时,查询只是
delete FROM countries.id=。如果调用Country.delete,则所有查询都是相同的,但没有
WHERE
子句。级联纯粹是在DB端完成的-Rails不知道它的存在。创建删除查询时,Postgres知道存在指向国家表的外键约束。当该外键在删除级联时设置为
Postgres将自动删除州上的行,并且由于城市也有外键约束(州上),这些行也将被删除。可以将其视为在删除行之前运行的DB触发器,以保持引用完整性。啊,好的,非常感谢。我看到活动记录批次的示例包括一个带有in_批次和delete_all的示例:
Person.where(“age>21”)。in_批次做| relation | relation.delete_all sleep(10)#限制删除查询结束
,该示例的效率不是比Person.where(“age>21”)。直接删除所有,因为没有in_批处理的代码只使用一个SQL查询?如果是这样的话,这个例子的目的是什么?在耗时的删除过程中提供非阻塞期?是的,它的效率较低。我想可能会有一些罕见的情况,你有数百万行,并希望这样做,但我认为这主要是一个连续的例子。
require 'rails_helper'

RSpec.describe Country, type: :model do
  describe "cascading delete" do
    let!(:country){ Country.create }
    let!(:state){ country.states.create }
    let!(:city){ state.cities.create }

    it "deletes the states" do
      expect {
        country.delete
      }.to change(State, :count).from(1).to(0)
    end

    it "deletes the cities" do
      expect {
        Country.delete_all
      }.to change(City, :count).from(1).to(0)
    end
  end
end
Country.where(evil: true).delete_all