为什么ActiveRecord不够聪明,不知道父亲的object_id应该等于其子节点的父节点的object_id?

@father = Hierarchy.find(:first, :conditions => ['label = ?', 'father']) @father.children.each do |child| puts @father.object_id == child.parent.object_id end 

我原以为这里的结果都是true

相反,他们都是false

为什么ActiveRecord以这种方式工作而不是认识到这些是相同的Ruby对象?

要在可能的情况下返回现有对象而不是创建新对象,ActiveRecord必须跟踪创建了哪些对象以及它们响应的数据库中的哪个条目,这将是一些开销。 即使这样,它仍然必须在数据库中查找child.parent才能知道它与@father代表的条目相同,因此从这个缓存中没有任何明显的增益性能(在ruby方面它保证分配多个对象但是以记账开销为代价,但在数据库方面它应该基本相同)。

因此,鉴于AR人员可能决定防止对应于相同数据库条目的不同对象要么是有害的,要么至少不值得努力,所以他们选择不这样做。

对于那些在被问到这些年后偶然发现的人(比如我!),请查看https://stackoverflow.com/a/4116397/1000655 。

它建议使用:inverse_of来设置双向关联。 我希望我过去没多次浏览过那么多文档!

对象ID是对象的指针(种类)。 rails对象的加载不会“共享”内存空间,因此当您执行child.parent时,您将获得父对象的副本。 要理解这一点 – 你可以做parent.something = foo,然后比较child.parent.something,你会发现它们是不同的。 您必须从数据库重新加载子项,然后才能将更改反映到父对象。

但是,您可能使用了错误的ID值。 如果需要ActiveRecord ID(例如SQL DBMS中ID列的值),请使用@ father.id == child.parent.id

重用对象是有问题的。 如果对模型实例进行更改,但在保存之前,还会执行另一个带回同一对象的查找,该怎么办? 新的应该反映数据库,但旧的应该仍然有更改的数据。

所以,是的,跟踪每个实例和每个实例中的脏字段将是一个很大的开销。 节省的内存不值得付出努力。

就我而言,AR至少应该支持身份地图插件。 这是我在处理AR时遇到的最大问题。 我意识到它增加了一些开销,但短暂的内存开销比数据库中的过度税收更好,因为它一次又一次地拉出相同的记录。 就像GC一样。 您可以自己完成,也可以使用高级语言将其抽象出来,以便您可以专注于业务逻辑。 你可以大惊小怪优化你的AR,或者你可以利用身份地图。