【问题标题】:delete_all vs destroy_all?delete_all vs destroy_all?
【发布时间】:2011-10-05 14:34:24
【问题描述】:

我正在寻找从表中删除记录的最佳方法。例如,我有一个用户,其用户 ID 跨越许多表。我想删除该用户以及所有表中具有其 ID 的每条记录。

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

这有效并从所有表中删除了用户的所有引用,但我听说destroy_all 的过程非常繁重,所以我尝试了delete_all。它只会从他自己的用户表中删除用户,并且将所有其他表中的id 设为空,但保留其中的记录完好无损。有人可以分享执行此类任务的正确流程吗?

我看到destroy_all 对所有关联对象调用了destroy 函数,但我只想确认正确的方法。

【问题讨论】:

    标签: ruby-on-rails ruby database activerecord


    【解决方案1】:

    你是对的。如果要删除用户和所有关联对象 -> destroy_all 但是,如果您只想删除用户而不抑制所有关联对象 -> delete_all

    根据这个帖子:Rails :dependent => :destroy VS :dependent => :delete_all

    • destroy / destroy_all: 关联对象通过调用其destroy方法与该对象一起销毁
    • delete / delete_all: 所有关联的对象都会立即销毁而不调用它们的 :destroy 方法

    【讨论】:

    • 还需要注意的是1)使用delete_all时不会调用回调,2)destroy_all实例化所有记录,一次销毁一个,所以对于非常大的数据集,这可能会非常缓慢。
    • 假设我在模型中运行 before_destroy 方法 - 如果我使用 delete_all 那么这个方法不会运行?其次,如果我在模型中使用 before_delete 方法,当我在 rails 控制台中运行 delete 或 delete_all 时,它会运行吗?
    【解决方案2】:

    delete_all 是一条 SQL DELETE 语句,仅此而已。 destroy_all 对 :conditions (如果有的话)的所有匹配结果调用 destroy() ,这可能至少是 NUM_OF_RESULTS SQL 语句。

    如果您必须在大型数据集上执行诸如 destroy_all() 之类的激烈操作,我可能不会从应用程序中执行此操作并小心手动处理。如果数据集足够小,您不会受到太大伤害。

    【讨论】:

      【解决方案3】:

      为避免destroy_all 实例化所有记录并一次销毁它们,您可以直接从模型类中使用它。

      所以不是:

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

      你可以这样做:

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

      结果是一次查询销毁所有关联记录

      【讨论】:

      • 它会在关联记录上调用销毁回调,还是UsageIndex.destroy_all 等同于UsageIntex.delete_all
      • UsageIndex.destroy_all 自 rails 3 起不再可用
      【解决方案4】:

      我制作了一个small gem,可以在某些情况下减少手动删除关联记录的需要。

      此 gem 为 ActiveRecord 关联添加了一个新选项:

      依赖: :delete_recursively

      当您销毁记录时,使用此选项关联的所有记录都将被递归删除(即跨模型),而不实例化任何记录。

      请注意,就像dependent: :delete 或dependent: :delete_all 一样,这个新选项不会触发依赖记录的around/before/after_destroy 回调。

      然而,在一个模型链中的任何地方都可以有dependent: :destroy 关联,否则这些关联是与dependent: :delete_recursively 关联的。 :destroy 选项将在任何地方正常工作,实例化和销毁所有相关记录,从而触发它们的回调。

      【讨论】:

      • 这太棒了!我想知道为什么没有更多的人在 github 上观看/加星标/分叉它。它仍然运作良好吗?
      • @Magne 谢谢!它应该工作。测试在 Ruby 2.4.1 和 Rails 5.1.1 上运行。到目前为止,我只是私下使用它,而不是在主要的生产应用程序中使用它,因此主要版本为“0”,但我从未注意到任何问题。它也相当简单,所以应该没问题。
      • 酷。 :) 我在 Ruby 2.3.1 和 'rails'、'~>4.1.14' 上运行一个项目,但遗憾的是,由于其他 gem,我不得不依赖 activerecord (~> 4.1.0)。我看到 delete_recursively 被解析为 0.9.0。是否有可以与 activerecord 4.1 一起使用的旧版本?我在 github 上的发布选项卡中找不到任何内容。
      • @Magne 我发现它实际上是works for activerecord as low as 4.1.14 并且已经发布了gem 1.0.0 版,它具有轻松的依赖关系。不过请记住,Rails 的 4.1 分支不再接收安全更新。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      • 1970-01-01
      • 2013-12-04
      相关资源
      最近更新 更多