thi*_*ign 5 ruby database activerecord ruby-on-rails
我知道关于这些主题的问题很多,但是我没有找到涵盖所有方面的问题。
考虑User,Activity和Like模型。当我查询一个活动时,我希望为集合中的每个活动加载第一个“赞”,而不会进行N + 1个查询,也不会加载过多的必要记录。我的代码如下所示:
class User < ActiveRecord::Base
has_many :likes, as: :liker
end
class Activity < ActiveRecord::Base
has_many :likes
has_one :first_like, -> { order(created_at: :asc) }, class_name: "Like"
end
class Like < ActiveRecord::Base
belongs_to :activity
belongs_to :liker, polymorphic: true
end
Run Code Online (Sandbox Code Playgroud)
我做了一个综合的要点来测试不同的加载策略和方法:https : //gist.github.com/thisismydesign/b08ba0ee3c1862ef87effe0e25386267
策略:N + 1个查询,左外部联接,单个额外查询
方法:eager_load,includes,includes & references,includes & preload(这将导致主要是左外连接或单额外的查询)
这是我发现的问题:
order(created_at: :asc)联接不尊重关联范围default_scope { order(created_at: :asc) }(请参阅:rails issue)。它确实遵守显式排序,即.order("likes.created_at asc")。limit(1)关联添加显式内容以希望限制单个额外的查询将破坏事情首选方法是仅查询所需记录的单个额外查询。总而言之,我找不到Rails的本地解决方案。有没有?
在我的问题中,我正在寻找一种使用 Rails 的本地方式。不过,这里有一个使用 SQL 和虚拟属性的解决方案:
class Activity < ApplicationRecord
has_one :first_like, class_name: "Like", primary_key: :first_like_id, foreign_key: :id
scope :with_first_like, lambda {
select(
"activities.*,
(
SELECT like_id as first_like_id
FROM likes
WHERE activity_id = activities.id
ORDER BY created_at ASC
LIMIT 1
)"
)
}
end
Activity.with_first_like.includes(:first_like)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |