egg*_*rop 35 database referential-integrity ruby-on-rails foreign-keys
如果我定义一个Customer和Order模型,其中Customer"有很多" Orders和Order"属于" Customer,在Rails中我们谈论Order有一个外键到Customer通过customer_id但我们并不是说这是在数据库中强制执行.
由于Rails没有将其定义为数据库级约束,因此存在数据完整性被违反的风险,可能在应用程序之外(或者如果同时收到请求,则在内部?),除非您手动在数据库中强制执行约束.
为什么Rails没有在数据库级别定义外键,或者有没有办法让Rails这样做?
class Customer < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :customer
end
ActiveRecord::Schema.define(:version => 1) do
create_table "customers", :force => true do |t|
t.string "name"
end
create_table "orders", :force => true do |t|
t.string "item_name"
t.integer "customer_id"
end
end
Run Code Online (Sandbox Code Playgroud)
Bil*_*win 22
Rails拥有一些约定,即应在应用程序中而不是在数据库中执行数据完整性.
例如,Rails甚至支持一些不能使用外键的数据库设计,例如Polymorphic Associations.
基本上,Rails约定将数据库视为静态数据存储设备,而不是活动的RDBMS.Rails 2.0 最终支持SQL数据库的一些更现实的功能.毫不奇怪,Rails的开发将比1.0版本更复杂.
Ian*_*ell 13
在解决了这个问题一段时间后,我认为不应该由数据库强制执行外键的核心Rails哲学的一部分.
应用程序级别验证和检查可以提供简单,快速,人类可读(思考错误消息)检查,这些检查在99.99%的时间内有效.如果您的应用程序需要更多,则应使用数据库级别约束.
我认为这种"哲学"的演变是因为使用了原始的测试框架:外键在使用灯具时被证明是一个巨大的麻烦.这就像"bug"成为"特征",因为没有人修复它.(如果我错过了历史记录,有人会纠正我.)
至少,Rails社区内有越来越多的运动来强制数据库的完整性. 查看上个月的这篇博文. 她甚至链接到一些插件,这些插件有助于提供处理错误的支持(以及另一个链接到更多插件的博客文章).再做一些谷歌搜索; 我见过其他插件,它们也增加了对迁移的支持以创建外键.
现在,是的,Rails核心理念的一部分是:不担心的东西,除非你确实需要.对于许多Web应用程序,如果一小部分(可能很小)的记录包含无效数据,则可能没问题.可能很少查看可能受影响的页面,或者可以优雅地处理错误.或者,随着应用程序的增长,在接下来的6个月内手工处理问题的成本也比现在花费在每个意外事件上的开发资源计划更便宜(如冷硬现金).基本上,如果你的用例没有让它看起来都很重要,它实际上只能由一个可能发生1/10000000请求的竞争条件引起......好吧,它值得吗?
因此我的预测是,默认情况下工具会更好地处理整个情况,最终这些工具将合并到Rails 3.同时,如果您的应用确实需要它,请添加它们.它会导致轻微的测试头痛,但是你无法通过模拟和存根来解决问题.如果你的应用程序真的不需要它......那么你已经很好了.:)
小智 6
经过几十年的行业发展,我坚信良好的数据库设计可以避免许多问题的应用,尤其是在经过增强的情况下.如果已知某个特定约束即使在编程单之后也会保持数据库的完整性(我确信我不是唯一一个这样做的人),那么如果可能的话,它应该应用于数据库.所以我鼓励人们尽可能使用外键.我还会考虑使用测试来提供数据完整性.因为我们都知道墨菲定律.