【问题标题】:Eager-load for custom joins in ActiveRecordActiveRecord 中自定义连接的急切加载
【发布时间】:2017-05-22 19:04:32
【问题描述】:

我有一张有很多预订的餐厅表。现在我想查询所有餐厅,如果他们有 2 人的预订,它应该预加载这些关联。如果 2 没有预订,它仍应返回餐厅,但关联为空。

为此,我尝试了以下查询:

Restaurant.eager_load(:reservations).where("number_of_people = ?", 2)

但是,这不起作用,因为它会丢弃所有有预订但没有一个是 2 人的餐厅。

所以我想做的是将该条件移动到连接条件中。比如:

Restaurant.joins('LEFT OUTER JOIN \"reservations\" ON \"reservations\".\"restaurant_id\" = \"restaurants\".\"id\" AND \"reservations\".\"number_of_people\" = ?', 2)

这将给出我需要的结果,但是这不是预加载“保留”关联,而是导致 N+1 问题。

eager_load 似乎不接受自定义查询。我找到了这些线程:https://github.com/rails/rails/issues/12270JOIN ON ... AND conditions when eager loading association in ActiveRecord,但没有提供解决方案。

【问题讨论】:

  • 你可以用includes代替joins
  • includes 也不接受自定义 SQL
  • 您需要创建一个与条件的新关联

标签: ruby-on-rails activerecord eager-loading


【解决方案1】:

我认为迪帕克是对的。 试试这个:

 #retaurant.rb
 has_many :reservations_for_two, ->{number_of_people: 2}, class_name: 'Reservation'

然后:

  Restaurant.preload(:reservations_for_two) #(for two separate queries)

   Restaurant.eager_load(:reservations_for_two) #(one join query)

【讨论】:

  • 我需要它是动态的,我可以指定 number_of_people 作为参数而不是硬编码它
【解决方案2】:

试试Restaurant.joins(:reservations).includes(:reservations).where("reservations.number_of_people = ?", 2)

【讨论】:

  • 这也只创建了一个“WHERE”语句,并没有将其置于“ON”条件中。
  • 好的,我知道你的问题了。第二个答案是正确的,就硬编码而言,一个肮脏的技巧是在您的模型类上创建一个 class has_many :reservations_for_x, ->{number_of_people: Restaurant.number_of_people_to_query}, class_name: 'Reservation' 之类的查询之前分配值,并且在急切加载之前将您的条件分配给类属性。
  • 这有效,但仅在单线程环境中有效。我担心竞争条件,因为它使用了一个类变量。
  • 没有测试,但似乎类级实例变量是线程安全的 (stackoverflow.com/questions/9558192/…)。或者,您可以使用Thread.current[:number_of_people_to_query] = 2,并在您的类中为其定义 getter 和 setter。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-17
  • 2016-01-28
  • 2010-12-01
  • 1970-01-01
相关资源
最近更新 更多