【问题标题】:Should I use ON DELETE CASCADE, :dependent => :destroy, or both?我应该使用 ON DELETE CASCADE、:dependent => :destroy 还是两者都使用?
【发布时间】:2009-07-27 18:57:42
【问题描述】:

在 Rails 应用程序中,我在 MySQL 中有外键约束,我手动设置它们,与我的迁移分开。

我想弄清楚是否应该使用 ActiveRecord 的 :dependent => :destroy 选项。例如,在我的架构中,我有表...

users
-----

log_entries
-----------
user_id  # Has FK constraint to users.id with ON DELETE CASCADE

在我的模型中,我可以...

class User < ActiveRecord::Base
  has_many :log_entries, :dependent => :destroy
end

我是否应该忽略模型上的依赖选项而将其留给数据库?还是把它放在那里好吗?删除此应用程序中的内容时,我不需要运行任何回调。在所有情况下,都可以简单地删除它们。

另一个需要考虑的因素是 FK 约束不会出现在我的测试环境中,这可能是因为 rake db:test:prepare 没有设置它们。因此,如果我完全依赖 MySQL 级联删除,很难测试会发生什么。

【问题讨论】:

    标签: mysql ruby-on-rails ruby activerecord


    【解决方案1】:

    如果您有带有 ON DELETE CASCADE 的 FK,则不应在模型中使用dependent => :destroy。它可以运行不必要的查询,而且你不能指望它将来不会破坏事情。您应该在模型文件中添加注释以记录它正在发生。不过。

    我还建议在迁移中执行 FK。如果您的测试数据库具有与生产数据库相同的约束,那就更好了,这可能会导致非常隐蔽的错误。有一个 RedHill 插件 (redhillonrails_core) 可以使迁移中的外键变得容易,并启用带有 FK 约束的模式转储,因此测试要简单得多。

    【讨论】:

    • 为什么不能指望它?这就像说你应该使用 model.to_json 因为不能保证它将来不会中断。
    • 如果你有另一层依赖,并且钩子决定自上而下删除它们,如果记录在它不期望的时候消失,它可能会在 nil 上调用方法。跨度>
    • 让您的数据库而不是 rails 应用程序来管理您的数据是有意义的。支持 on delete 级联的用法。不应该将 schema_format 设置为 :sql 修复测试数据库问题不存在的 on delete 级联吗?
    • redhillonrails_core 将 FK 支持添加到默认模式转储中,我更喜欢设置 schema_format。
    【解决方案2】:

    我会在此处添加 :dependent => :destroy 只是因为它传达了意图。更重要的是,并非所有数据库都支持 DELETE CASCADE,因此数据库适配器将负责确定如何最好地删除关联的记录。在我看来,至少把它放在模型中更为重要。但把它放在两者中是正确的答案。

    【讨论】:

    • 完全同意你的看法。我相信 APPLICATION 端模型依赖项是必须具备的部分,因为它不会将应用程序与数据库绑定。而 DATABASE 端级联删除只是确保您在直接使用数据库时不会遇到任何问题。
    【解决方案3】:

    视情况而定。 :dependent => :destroy 将加载每个子模型并运行回调。 ON DELETE CASCADE 不运行任何回调,但速度极快。

    如果您只想摆脱模型,ON DELETE CASCADE 可能是要走的路,或者使用 :dependent => :delete_all,它只会运行 1 个查询,而不是 N+1。

    【讨论】:

    • 在我看来,这是一种权衡。一方面,您可以以闪电般的速度销毁数据,而忽略所有业务规则。另一个很慢(可能真正很慢),但要尊重业务逻辑。这两种方法对我都有效。
    猜你喜欢
    • 2017-08-29
    • 2011-08-28
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多