【发布时间】:2016-05-23 21:07:46
【问题描述】:
我正在使用 AR includes 方法在对象 User 和 Building 之间执行 LEFT OUTER JOIN,其中用户可能有也可能没有 Building 关联:
users = User.includes(:building).references(:buildings)
由于我使用的是references,任何关联的建筑对象都将被预先加载。
我的期望是,然后我能够遍历用户列表,并检查用户是否有与之关联的建筑物而不触发其他查询,但事实上,每当我尝试访问建筑物属性时,我都会看到这一点对于没有的用户,AR 会进行另一个 SQL 调用以尝试检索该建筑物(尽管在随后的尝试中它只会返回 nil)。
这些查询显然是多余的,因为关联将在初始连接期间加载,并且似乎破坏了使用包含/引用进行急切加载的整个目的,因为现在我正在查看 N 倍的查询数量等于空关联的数量。
users.each do | user |
# This will trigger a new query when building is not present:
# SELECT "buildings".* FROM "buildings" WHERE "buildings"."address" = $1 LIMIT 1 [["address", "123 my street"]]
if user.building
puts 'User has building'
else
puts 'User has no building'
end
end
用户类别:
class User < ActiveRecord::Base
belongs_to :building, foreign_key: 'residence_id'
end
有没有办法在不触发额外查询的情况下检查用户的建筑关联是否存在?
在铁路 4.2.0 / POSTGRES
更新:
感谢@BoraMa 整理了这个test。看起来我们在最近的 Rails 版本中得到了不同的行为:
输出(轨道 4.2.0):
User 1 has building
User 2 has building
User 3 has no building
D, [2016-05-26T11:48:38.147316 #11910] DEBUG -- : Building Load (0.2ms) SELECT "buildings".* FROM "buildings" WHERE "buildings"."id" = $1 LIMIT 1 [["id", 123]]
User 4 has no building
输出(轨道 4.2.6)
User 1 has building
User 2 has building
User 3 has no building
User 4 has no building
输出(轨道 5.0.0)
User 1 has building
User 2 has building
User 3 has no building
User 4 has no building
外卖:
- 此问题仅限于“悬空外键(即 Residence_id column 不是 nil 但没有对应的建筑对象)" (感谢@FrederickCheung)
- 自 Rails 4.2.6 起,该问题已得到解决
【问题讨论】:
-
我预计会出现类似于“ActiveRecord::AssociationNotFoundError: Association named 'buildings' was not found on User”的错误。你能确认查询语法以及用户->建立关联定义吗?
-
@messanjah 我个人希望
user.building在关联不存在的情况下返回 nil,这就是后续调用中发生的情况,但在第一次调用时它总是会触发 SQL 查询。跨度> -
奇怪,我没有观察到这种行为——我的 nil 关联只是返回 nil,没有进一步的查询。您在问题中给出的代码确实是该问题的最小工作示例吗?
-
您是否有“悬空”外键(即 Residence_id 列不为零但没有对应的建筑对象)?
-
@Yarin,请参阅this gist 进行最少的可运行测试。我在带有 Postgres 的 Rails 4.2.6 上试过这个,仍然看不到其他查询。请尝试在您的系统上运行它并告诉我们它是否仍然存在错误,如果没有,请尝试更新它,以便它实际执行多余的查询。也许还发布两个表的架构(但我自己不确定它是否相关)。
标签: sql ruby-on-rails ruby ruby-on-rails-4 rails-activerecord