[英]ActiveRecord : LEFT OUTER self-JOIN with conditions on joined table
我有一個帶有自反關聯的ActiveRecord類( 注意:出於非公開的原因,類名被刪除 ):
class Thing < ActiveRecord::Base
belongs_to :parent,
class_name: 'Thing'
has_many :children,
class_name: 'Thing',
foreign_key: :parent_id
scope :children, ->{ where(arel_table[:parent_id].not_eq(nil)) }
end
我想讓所有孩子,在外部與他們的父母保持聯系,並在父母存在的情況下對父母附加條件,同時仍然渴望加載父母。
通常在這種情況下,我會執行以下操作:
Thing.includes(:other_thing).merge(OtherThing.some_scope)
但是在這種情況下是不可能的:因為這是自連接,所以如果我合並Thing
的作用域,則條件將適用於孩子的東西,而不適用於父母的東西。
我試圖在原始SQL中執行此操作:
scope :some_scope, ->{
children.joins(<<-SQL).references(:parent)
LEFT OUTER JOIN things AS parents
ON things.parent_id = parents.id
AND parents.some_field IN ('foo', 'bar')
SQL
}
該查詢是可以的,但是似乎父級並沒有急於加載(嘗試在此作用域上map(&:parent)
時有n + 1個查詢)。
就目前而言,我或多或少的工作解決方案是使用子查詢(拔出與父項條件匹配的ID,然后parent_id IN
此集合中選擇具有parent_id IN
子項),但我想知道是否存在更合適的/優雅的。
我還沒有找到一種使用merge
(似乎堅持使用table_name模型),但是您可以使用includes
並圍繞期望的別名構建條件-您需要根據以下內容修改此別名您自己的命名:
User.includes(:parent).
where('parents_users.some_field IN (?)', ['foo', 'bar']).
references(:parents_users)
但是,您可能需要注意NULL父ID,因為該條件將添加到WHERE子句中,而不是添加到LEFT JOIN本身中:
User.includes(:parent).
where('parents_users.some_field IN (?) OR parents_users.id IS NULL', ['foo', 'bar']).
references(:parents_users)
這應該正確執行所有急切的加載。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.