更新内存中的eager-loaded关联

时间:2009-04-17 10:00:34

标签: ruby-on-rails activerecord associations eager-loading

在我目前的rails应用程序中,我将大量数据从数据库中提取到内存中,这样我就可以开始一个长时间运行的后台任务,我不想每5秒就打一次数据库。

这一切都很好但我有一些不太优雅的代码,如果可能我想摆脱它。

举个例子,我的情况是我有一个User模型,User模型可以以Contacts的形式链接到其他User模型,而后者又可以链接回第一个User模型,依此类推。这模仿如下(感谢Milan Novota的早期帮助): -

class User < ActiveRecord::Base
  has_many :contact_records, :foreign_key => :owner_id
  has_many :contacts, :through => :contact_records, :class_name => "User"
end

class ContactRecord < ActiveRecord::Base
  belongs_to :owner, :class_name => "User"
  belongs_to :user
end

所以现在我可以输入

user_a_contacts = user_a.contact_records
=> [user_b, user_c]

并获取用户a的所有联系人。现在让我们说我希望通过用户a获取用户b的联系人(想不到我为什么会这样,但这只是一个例子!)

user_b_contacts = user_a_contacts.first.contact_records
=> [user_a, user_c]

现在我可以获得用户的名字(在一个错综复杂的环形交叉口中,永远不会在现实世界中使用)

user_a_name = user_b_contacts.first.name
=> "Jamie"

到目前为止,这么好。现在我更改了用户的名字

user_a.name = "Sandy"
=> "Sandy"

如果像以前一样从数据库中再次访问用户的名字

user_a_name = user_b_contacts.first.name
=> "Sandy"

但是,如果我渴望加载并将此值保存在内存中,我会得到

user_a_name = user_b_contacts.first.name
=> "Jamie"

但是做以下事情给了我正确的答案

user_a.name
=> "Sandy"

显然,热切加载是为原始用户创建不同的User对象,以及从ContactRecord对象中加载的用户对象。

所以(终于!)我的问题是: -

目前,我已经使用

来解决这个问题
@users.each.detect{|user| user == user_b_contacts.first}

(其中@users是用户对象的急切加载列表)。有没有办法可以更新急切加载的用户对象?

请注意: -

a)我正急着使用以下

加载
User.find(:all, :include => [ {:contact_records => :contacts] } ])

b)显然这不是我正在使用的实际代码,但为了展示代码会有更多的解释和说明,我觉得我已经厌倦了你!相信我使用DOES的真实示例需要这种结构才能正常工作,尽管看起来很奇怪! ;)

c)我可能在重构示例时引入了拼写错误和错误,但请忽略它们。我需要知道的是,是否可以在不命中数据库的情况下重新加载热切的用户。

非常感谢提前!

更新:如下所述,在流程运行结束之前,模型数据不会保存到数据库中,因此重新加载将无法正常工作,因为数据库中的数据不会发生变化。

2 个答案:

答案 0 :(得分:4)

行。我将把你的问题浓缩成一个新问题并回答那个问题。如果我误解了,请原谅我,这不是你要问的。

<强>问题

  

如果user是一个ActiveRecord模型,我在contacts之前加载了User.first(:include => :contacts)关联,那么当contacts关联更改时,如何刷新user.reload 关联数据库?

<强>答案

您可以通过我所知的两种方式使关联缓存无效。首先你可以做到:

user.clear_association_cache

将从头开始重新加载整个用户模型。一个稍微不那么激烈的方法是做

user

不会重新加载所有user.contacts,但会清除缓存的关联。

无论哪种方式,下次执行{{1}}时,都会从数据库中重新加载它们。

答案 1 :(得分:0)

非常感谢你的回复,丹尼尔。虽然你没有得到正确的问题,但你让我意识到我错过了一个关键点!数据库记录不会更新,因为我没有保存!在任何时候。

我正在做的主要是将模型数据拉出到实例变量中,以加快后台进程。因此,在流程运行结束之前,第一次加载的数据将不会保存回数据库。

我希望的是一种方法,您可以在急切加载时指定一列的值与已加载的另一个模型相关。

例如,

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ])

或类似的。

据我所知,Rails中没有这样的语法,但是我希望我错了! :)

希望这会让它更清晰一些,再次感谢你的回复。