为啥 ORM 不自动在内存中设置反向关联?
Posted
技术标签:
【中文标题】为啥 ORM 不自动在内存中设置反向关联?【英文标题】:Why don't ORMs automatically set inverse associations in memory?为什么 ORM 不自动在内存中设置反向关联? 【发布时间】:2012-10-04 17:23:06 【问题描述】:考虑以下人为的例子:
class Company < ActiveRecord::Base
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :company
end
c, p = Company.new, Project.new
c.projects << p
p.company => c
当项目被添加到集合中时,Rails 会自动设置与公司的反向关联。不幸的是,这是唯一一次 Rails 足够聪明地做到这一点。对方的赋值不会将对象添加到逆向集合中。
c, p = Company.new, Project.new
p.company = c
c.projects => []
多对多关系也不进行任何自动反向引用分配。 ActiveRecord 和 DataMapper 都表现出这种行为。这有技术原因吗?在保存和重新加载发生之前保持一致的关联会大大加快某些测试用例的速度,并且总体上会使事情变得更简洁。
【问题讨论】:
您可能不应该养成在一行中初始化多个对象的习惯,就像您在这里使用c
和p
所做的那样。这最终会导致难以维护的代码。
@tadman 你能证明这种说法吗?
如果您稍后在 new
调用中添加参数会发生什么?然后你最终会一团糟。最好每行初始化一个对象。 ,
符号通常保留用于交换 (a,b = b,a
) 或解包返回值 (a,b = foo(...)
)。这也意味着您需要阅读和匹配c
和Company.new
、p
和Project.new
,这在根本不应该棘手的事情上增加了很多上下文开销。这将如何与三个、四个或五个初始化一起工作?丑,确实。任何导致混乱或容易出错的事情充其量都是有风险的。
当你觉得它太难理解时,为什么不把它们分解成单个作业呢?此外,听起来真正的罪魁祸首是您需要将如此多的属性传递给您的方法。我浏览了我最近的两个宝石,只发现两个地方 1 2 我需要分配超过 2 个值。我选择了在上下文中有意义的东西。
【参考方案1】:
您误解了这两个操作的作用,尽管它是一种微妙的效果,在文档中可能没有清楚地传达。
<<
运算符不仅为您的项目分配company_id
,而且如果记录存在,它也会保存它。它还会将此添加到公司模型的projects
缓存中。
company=
方法只分配对象,不进行对象间通信。无法按您的意愿加载未保存的记录。这些记录实际上都不在数据库中,因此c.projects
将是一个空数组,除非您像第一种情况那样明确地向其中添加了一些内容。
通常未保存的对象的行为不如它们的数据库持久对象。
【讨论】:
就缓存关联而言,我看不出未保存对象与其持久对象相比表现不同的原因。 理论上可以,但在实践中实现起来可能会很棘手。如果您有野心,可以尝试将此行为作为补丁添加并提交至the Rails GitHub project 或将其作为独立的 gem 发布。【参考方案2】:见https://github.com/rails/rails/pull/9522。自动反向关联可能会成为 Rails 未来版本的一项功能。
【讨论】:
以上是关于为啥 ORM 不自动在内存中设置反向关联?的主要内容,如果未能解决你的问题,请参考以下文章
为啥Html中在table标签中设置居中并不显示居中,在单个tr标签中设置才显示居中