我应该使用ON DELETE CASCADE,:dependent => :destroy还是两者都用?

3
在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

我应该在模型中省略dependent选项,让它由数据库自行处理吗?还是最好将其包含在内?在这个应用程序中,我不需要在删除内容时运行任何回调。在所有情况下,直接删除即可。
另一个要考虑的因素是,在我的测试环境中,FK约束可能不存在,因为“rake db:test:prepare”没有设置它们。因此,如果完全依赖MySQL来级联删除,很难测试出会发生什么。
3个回答

7
如果您的模型中有ON DELETE CASCADE的外键,请勿使用dependent => :destroy。它会运行不必要的查询,并且未来可能会出现问题。请在模型文件中添加注释以记录其发生情况。我还建议在迁移中进行外键约束。如果测试数据库与生产数据库具有相同的约束条件,则可以避免非常难以调试的错误。使用RedHill插件(redhillonrails_core)可以轻松创建迁移中的外键,并启用带有FK约束的模式转储,因此测试更加简单。

为什么你不能依赖它?这就像说你应该使用 model.to_json,因为没有保证它不会在未来出现问题。 - Aaron Rustad
如果您有另一层依赖关系,并且钩子决定自上而下删除它们,那么如果记录在它不希望它们消失时消失,它可能会在nil上调用方法。 - Michael Sofaer
让数据库管理数据比让Rails应用程序管理数据更有意义。赞同使用on delete cascade。将schema_format设置为:sql不应该解决测试数据库中缺少on delete cascade的问题吗? - Omar Qureshi
redhillonrails_core为默认模式转储添加了外键支持,我更喜欢这种方式而不是设置模式格式。 - Michael Sofaer

3

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


完全同意你的观点。我认为应用程序侧的模型依赖是必不可少的,因为它不会将应用程序与数据库绑定在一起。而数据库侧的级联删除只是确保在直接使用数据库时不会出现任何问题。 - Rustam Gasanov

3

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

如果你只想要摆脱这些模型,使用 ON DELETE CASCADE 可能是最好的选择,或者使用 :dependent => :delete_all,它只会运行 1 次查询,而不是 N+1 次查询。


1
在我看来,这是一种权衡。一方面,你可以使用闪电般快速的方式销毁数据,无视所有业务规则。另一方面,虽然可能会很慢(真的很慢),但它尊重业务逻辑。对我来说,这两种方法都是有效的。 - lsdr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接