我尝试使用where子句刷新ActiveRecord has_many关联。我发现了两件令我困惑的事情:
(1)是预期的行为吗? [更新 - 请参阅下面的Frederick Cheung的回答;每个电话会产生一个新的关系,所以我相信答案是肯定的]我无法在文档中找到这个,所以我觉得如果依靠我的观察。如果是,则(2)没有实际意义,因为AR每次都会查询数据库,而不会告诉它强制重新加载。但是,由于我不知道,我有后续问题,如果(1)无法保证:如何在没有立即执行查询的情况下强制重新加载?
为了说明(输出被抑制,因为它们不相关,只显示AR日志输出):
MediaFile
has_many :assets
缓存和强制刷新按预期工作:
m = MediaFile.delivered.offset(20).last
### log suppressed
1.9.3-p448 :078 > m.assets.map(&:id); nil
MediaAsset Load (0.3ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849)
1.9.3-p448 :079 > m.assets.map(&:id); nil
1.9.3-p448 :080 > m.assets(true).map(&:id); nil
MediaAsset Load (0.3ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849)
where
子句强制db fetch:
1.9.3-p448 :081 > m.assets.where(type: "Source").map(&:id); nil
MediaAsset Load (0.3ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849) AND (`media_assets`.`type` = 'Source')
1.9.3-p448 :082 > m.assets.where(type: "Source").map(&:id); nil
MediaAsset Load (0.3ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849) AND (`media_assets`.`type` = 'Source')
将true传递给关联方法会强制立即加载:
1.9.3-p448 :083 > m.assets(true).where(type: "Source").map(&:id); nil
MediaAsset Load (0.3ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849)
MediaAsset Load (0.2ms) SELECT `media_assets`.* FROM `media_assets` WHERE (`media_assets`.media_file_id = 533849) AND (`media_assets`.`type` = 'Source')
请注意,最后一个示例中的第一个查询首先执行而没有where子句。这似乎不是最理想的。
答案 0 :(得分:2)
首先,假设where
子句强制刷新是不正确的 - 对于活动记录,这两个只是单独的关系,而一个被加载的另一个没有发生。如果保持这种关系,它只会加载一次,例如
rel = m.assets.where(type: 'Source'); nil
rel.map(&:id)
rel.map(&:id)
只能访问数据库一次。
您可以通过调用reset来清除关联缓存:
m.assets.reset
(但是,由于这会返回关联,因此在控制台中这将触发重新加载,除非您附加;false
或类似内容)