我如何在多态的条件下急切加载和加入?
How can I eager load and join on a condition for a polymorphic?
这是我的模型:
class Team < ApplicationRecord
has_many :team_permissions
end
class TeamPermission < ApplicationRecord
belongs_to :team
belongs_to :permissible, polymorphic: true
end
class User < ApplicationRecord
has_many :team_permissions, as: :permissible
end
我知道你可以像这样使用 include 来解决你的 N+1 问题:
Team.includes(team_permissions: :permissible)
现在,我只想加入一个条件下的权限。例如,如果它们不属于一组 id,那么我希望它能工作,但会引发错误。
ActiveRecord:
Team.includes(team_permissions: :permissible).where.not(team_permissions: { id: team_permission_ids })
Error:
ActionView::Template::Error (Cannot eagerly load the polymorphic association :permissible):
进一步研究,我发现下面的方法按照我想要的方式工作,但它没有解决 N+1 问题。
Team.includes(:team_permissions).where.not(team_permissions: { id: team_permission_ids })
我如何为 .includes
包含预加载条件?
不幸的是,Active Record 不够聪明(老实说,也不够信任),无法计算出它需要加入第一个 table 才能应用您的条件,而不是第二个。
你应该可以通过稍微明确一点来帮助解决这个问题:
Team.
includes(:team_permissions). # or eager_load(:team_permissions).
preload(team_permissions: :permissible).
where.not(team_permissions: { id: team_permission_ids }
当没有条件引用 includes
tables 时,默认行为是使用 preload
,它通过执行单个附加查询来处理 N+1,并且是与多态关联兼容。然而,当发现这样的条件时,all includes
被转换为 eager_load
,它在主查询中执行 LEFT JOIN(因此不兼容:无法编写连接到我们甚至还不知道的 tables 的查询。
上面,我已经分离了我们确实想要通过 preload
加载的部分,所以它应该做正确的事情。
这是我的模型:
class Team < ApplicationRecord
has_many :team_permissions
end
class TeamPermission < ApplicationRecord
belongs_to :team
belongs_to :permissible, polymorphic: true
end
class User < ApplicationRecord
has_many :team_permissions, as: :permissible
end
我知道你可以像这样使用 include 来解决你的 N+1 问题:
Team.includes(team_permissions: :permissible)
现在,我只想加入一个条件下的权限。例如,如果它们不属于一组 id,那么我希望它能工作,但会引发错误。
ActiveRecord:
Team.includes(team_permissions: :permissible).where.not(team_permissions: { id: team_permission_ids })
Error:
ActionView::Template::Error (Cannot eagerly load the polymorphic association :permissible):
进一步研究,我发现下面的方法按照我想要的方式工作,但它没有解决 N+1 问题。
Team.includes(:team_permissions).where.not(team_permissions: { id: team_permission_ids })
我如何为 .includes
包含预加载条件?
不幸的是,Active Record 不够聪明(老实说,也不够信任),无法计算出它需要加入第一个 table 才能应用您的条件,而不是第二个。
你应该可以通过稍微明确一点来帮助解决这个问题:
Team.
includes(:team_permissions). # or eager_load(:team_permissions).
preload(team_permissions: :permissible).
where.not(team_permissions: { id: team_permission_ids }
当没有条件引用 includes
tables 时,默认行为是使用 preload
,它通过执行单个附加查询来处理 N+1,并且是与多态关联兼容。然而,当发现这样的条件时,all includes
被转换为 eager_load
,它在主查询中执行 LEFT JOIN(因此不兼容:无法编写连接到我们甚至还不知道的 tables 的查询。
上面,我已经分离了我们确实想要通过 preload
加载的部分,所以它应该做正确的事情。