nva*_*ano 12 ruby activerecord ruby-on-rails preloading
我有Place模型和Event模型.地方可以在特定日期举办活动.
如何设置我的关联和查找器来加载所有位置,包括(急切加载)他们在特定日期的事件而没有N + 1查询问题?
我尝试过的:
class Place
has_many :events
end
Place.all.preload(:events).where("events.start_date > '#{time_in_the_future}'")
#ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "events".
Place.all.includes(:events).where("events.start_date > '#{time_in_the_future}'").references(:event)
# only loads places that have an event at the specific date and not all places including their events (if there are any events).
Run Code Online (Sandbox Code Playgroud)
我成功地想出了一个能做我想要的但不是动态的关联(不接受参数)
class Place
has_many :events, -> {where("events.start_date > '#{Time.now}'")}
end
Place.all.preload(:events)
# perfect: executes two queries: One to get all 'places' and one to get all 'events' that belong to the places and merges the 'events' into the 'place' objects.
# But I can't pass time as a parameter, so time is always Time.now (as specified in the has_many association).
# Place.all.preload(:events).where(xyz) gives wrong results like the examples above.
Run Code Online (Sandbox Code Playgroud)
对我来说问题是我无法找到一种方法来预加载/急切加载动态条件.因为preload和includes期望关联名称作为参数,并且不能使用参数进行细化.至少我发现没有办法做到这一点.
这似乎是唯一有效的解决方案:
# 1st query: load places
places = Place.all.to_a
# 2nd query: load events for given places, matching the date condition
events = Event.where(place: places.map(&:id)).where("start_date > '#{time_in_the_future}'")
events_by_place_id = events.group_by(&:place_id)
# 3: manually set the association
places.each do |place|
events = events_by_place_id[place.id] || []
association = place.association(:events)
association.loaded!
association.target.concat(events)
events.each { |event| association.set_inverse_instance(event) }
end
Run Code Online (Sandbox Code Playgroud)
这有点笨拙,但很容易适应您可能希望使用单独的查询加载关联然后将其附加到现有对象的任何情况。
| 归档时间: |
|
| 查看次数: |
4128 次 |
| 最近记录: |