[英]Problems with Rails 3 Active Record Query Interface with join on ID
我一直在與Rails 3活動記錄查詢接口有問題。 我有一個查找表(lookups),一個主表(through_references)和一個通過/聯接表through_tables。 因此,這是我使用has_many:through設置的HABTM配置。
更新:這里要特別注意的是,當我執行這些聯接時,我一直在聯接ID,以提供記錄過濾。 看來這不適用於Active Record查詢接口。 如果您不想查看我的工作的血腥細節,可以跳到下面查看我的解決方法。
我們還將有許多主要項(through_references表)應該可以具有查找項的任意組合,並可以方便地單擊相關的查找項,例如復選框。
我已將代碼發布在github上 。 github源代碼上有很多解釋。 要查看結果,請轉到查找索引頁面。 請注意,您將需要使用腳手架代碼創建記錄。
我還擁有在heroku上運行的代碼,以及更多的解釋和示例。
class Lookup < ActiveRecord::Base
has_many :fk_references
has_many :through_tables
has_many :through_references, :through => :through_tables
attr_accessible :name, :value
end
class ThroughTable < ActiveRecord::Base
belongs_to :through_reference
belongs_to :lookup
attr_accessible :description, :through_reference_id, :lookup_id
end
class ThroughReference < ActiveRecord::Base
has_many :through_tables
has_many :lookups, :through => :through_tables
attr_accessible :description
end
如果我們想列出所有查找項目以及與之對應的主要項目,則可以將“查找”表與主要項目(through_references)表一起加入。 對應的SQL:
SELECT * FROM lookups
LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)
LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id
ORDER BY lookups.id
返回記錄:
1;“Lookup Item 1”;“1”;“2012-06-06 17:14:40.819791”;“2012-06-06 17:14:40.819791”;1;1;1;“Main Item 1 has Lookup item 1”;“2012-06-06 17:17:31.355425”;“2012-06-06 17:17:31.355425”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
2;“Lookup Item 2”;“2”;“2012-06-06 17:14:59.584756”;“2012-06-06 17:14:59.584756”;;;;“”;“”;“”;;“”;“”;“”
3;“Lookup Item 3”;“3”;“2012-06-06 17:15:14.700239”;“2012-06-06 17:15:14.700239”;2;1;3;“Main Item 1 has Lookup item 3”;“2012-06-06 17:17:53.169715”;“2012-06-06 17:17:53.169715”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
這是我所期望的。
===使用自定義左聯接的Active Record查詢接口
Lookup.joins(“LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)” ).includes(:through_references).order(‘lookups.id’)
從Active Record查詢界面返回的內容(請注意,我向下瀏覽Active Record層次結構):
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
2 Lookup Item 2 2 4 Main Item 2 has Lookup item 2 2 Main Item 2
3 Lookup Item 3 3 2 Main Item 1 has Lookup item 3 1 Main Item 1
這不是我所期望的。
我們這里擁有的內容與簡單的左連接(沒有AND子句)相同。 這告訴我在Active Record查詢接口中AND子句被忽略。
===使用find_by_sql方法的活動記錄查詢接口
Lookup.find_by_sql("SELECT * FROM lookups LEFT OUTER JOIN through_tables ON (through_tables.lookup_id = lookups.id AND through_tables.through_reference_id = 1) LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id ORDER BY lookups.value, through_references.id" )
從Active Record查詢界面返回的內容(請注意,我向下瀏覽Active Record層次結構):
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
Lookup Item 2 2 No through_tables entry
1 Lookup Item 3 3 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 3 3 1 Main Item 1 has Lookup item 1 1 Main Item 1
這里的結果太瘋狂了!
這是一個錯誤,是預期的效果,還是我缺少了什么?
我希望有一個干凈的方法,而不必生成兩個結果集,並通過代碼合並它們。
我找到了一種解決方法。 問題似乎是Active Record無法識別對ID進行過濾的聯接(LEFT OUTER JOIN xyz ON xyz.id = ID)。
我的變通辦法涉及創建一個存儲過程或函數,該過程將ID作為參數,在數據庫中進行聯接,並返回一個不錯的平面記錄集。
請參閱: Heroku演示頁面(跳到底部)
請注意,我沒有將其標記為解決方案,因為這是一種變通方法,並且與活動記錄無關。
好吧,閱讀github項目,我看到了:
我真正想做的是擁有所有查找項目的列表,如果有匹配的Main Items,請將它們附加到返回的記錄上,否則,我希望為null。 這是我使用了10多年的技術。
我在想這個問題恰恰是您想要這樣做,那時候讓渴望加載的Rails處理它會更自然,因此您已經將注意力集中在通過單個大規模連接獲取所有內容上。
我要做的是這樣的:
Lookup.where(..在此處插入任何需要的條件...)。includes(:through_tables)
然后,ActiveQuery將在一個查詢中獲取所有Lookup,然后使用預先加載來獲取包含語句中命名的任何關聯,每個關聯一個查詢。
請注意,我並不是說聯接是不好的,只是說這是在Rails中進行連接的更自然的方法。 我喜歡使用Preloader http://apidock.com/rails/ActiveRecord/Associations/Preloader將需要加載哪些內容的決定與要獲取哪些數據的決定區分開來。 我發現這對控制器很有幫助-讓模型決定條件是什么,但讓控制器決定需要加載哪些對象。
高溫超導
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.